Skip to content

Commit e669ffa

Browse files
author
Dave Bartolomeo
authored
Merge pull request #8320 from jketema/structured-binding-array
C++: Handle initialization of structured bindings via bitwise copy in extractor
2 parents f6681f3 + d51cbe2 commit e669ffa

9 files changed

+540
-0
lines changed

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

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12820,6 +12820,221 @@ ir.cpp:
1282012820
# 1668| Type = [IntType] int
1282112821
# 1668| ValueCategory = prvalue(load)
1282212822
# 1670| getStmt(3): [ReturnStmt] return ...
12823+
# 1672| [TopLevelFunction] void array_structured_binding_non_ref_init()
12824+
# 1672| <params>:
12825+
# 1672| getEntryPoint(): [BlockStmt] { ... }
12826+
# 1673| getStmt(0): [DeclStmt] declaration
12827+
# 1673| getDeclarationEntry(0): [VariableDeclarationEntry] definition of xs
12828+
# 1673| Type = [ArrayType] int[2]
12829+
# 1673| getVariable().getInitializer(): [Initializer] initializer for xs
12830+
# 1673| getExpr(): [ArrayAggregateLiteral] {...}
12831+
# 1673| Type = [ArrayType] int[2]
12832+
# 1673| ValueCategory = prvalue
12833+
# 1673| getElementExpr(0): [Literal] 1
12834+
# 1673| Type = [IntType] int
12835+
# 1673| Value = [Literal] 1
12836+
# 1673| ValueCategory = prvalue
12837+
# 1673| getElementExpr(1): [Literal] 2
12838+
# 1673| Type = [IntType] int
12839+
# 1673| Value = [Literal] 2
12840+
# 1673| ValueCategory = prvalue
12841+
# 1674| getStmt(1): [DeclStmt] declaration
12842+
# 1674| getDeclarationEntry(0): (no string representation)
12843+
# 1674| Type = [ArrayType] int[2]
12844+
# 1674| getVariable().getInitializer(): [Initializer] initializer for (unnamed local variable)
12845+
# 1674| getExpr(): [VariableAccess] xs
12846+
# 1674| Type = [ArrayType] int[2]
12847+
# 1674| ValueCategory = prvalue(load)
12848+
# 1674| getDeclarationEntry(1): [VariableDeclarationEntry] definition of x0
12849+
# 1674| Type = [IntType] int
12850+
#-----| getVariable().getInitializer(): [Initializer] initializer for x0
12851+
#-----| getExpr(): [ArrayExpr] access to array
12852+
#-----| Type = [IntType] int
12853+
#-----| ValueCategory = lvalue
12854+
#-----| getArrayBase(): [VariableAccess] (unnamed local variable)
12855+
#-----| Type = [ArrayType] int[2]
12856+
#-----| ValueCategory = lvalue
12857+
#-----| getArrayOffset(): [Literal] 0
12858+
#-----| Type = [LongType] unsigned long
12859+
#-----| Value = [Literal] 0
12860+
#-----| ValueCategory = prvalue
12861+
#-----| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
12862+
#-----| Type = [IntPointerType] int *
12863+
#-----| ValueCategory = prvalue
12864+
# 1674| getDeclarationEntry(2): [VariableDeclarationEntry] definition of x1
12865+
# 1674| Type = [IntType] int
12866+
#-----| getVariable().getInitializer(): [Initializer] initializer for x1
12867+
#-----| getExpr(): [ArrayExpr] access to array
12868+
#-----| Type = [IntType] int
12869+
#-----| ValueCategory = lvalue
12870+
#-----| getArrayBase(): [VariableAccess] (unnamed local variable)
12871+
#-----| Type = [ArrayType] int[2]
12872+
#-----| ValueCategory = lvalue
12873+
#-----| getArrayOffset(): [Literal] 1
12874+
#-----| Type = [LongType] unsigned long
12875+
#-----| Value = [Literal] 1
12876+
#-----| ValueCategory = prvalue
12877+
#-----| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
12878+
#-----| Type = [IntPointerType] int *
12879+
#-----| ValueCategory = prvalue
12880+
# 1675| getStmt(2): [ReturnStmt] return ...
12881+
# 1677| [CopyAssignmentOperator] CapturedLambdaMyObj& CapturedLambdaMyObj::operator=(CapturedLambdaMyObj const&)
12882+
# 1677| <params>:
12883+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
12884+
#-----| Type = [LValueReferenceType] const CapturedLambdaMyObj &
12885+
# 1677| [MoveAssignmentOperator] CapturedLambdaMyObj& CapturedLambdaMyObj::operator=(CapturedLambdaMyObj&&)
12886+
# 1677| <params>:
12887+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
12888+
#-----| Type = [RValueReferenceType] CapturedLambdaMyObj &&
12889+
# 1677| [CopyConstructor] void CapturedLambdaMyObj::CapturedLambdaMyObj(CapturedLambdaMyObj const&)
12890+
# 1677| <params>:
12891+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
12892+
#-----| Type = [LValueReferenceType] const CapturedLambdaMyObj &
12893+
# 1677| [MoveConstructor] void CapturedLambdaMyObj::CapturedLambdaMyObj(CapturedLambdaMyObj&&)
12894+
# 1677| <params>:
12895+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
12896+
#-----| Type = [RValueReferenceType] CapturedLambdaMyObj &&
12897+
# 1680| [Constructor] void CapturedLambdaMyObj::CapturedLambdaMyObj()
12898+
# 1680| <params>:
12899+
# 1680| <initializations>:
12900+
# 1680| getEntryPoint(): [BlockStmt] { ... }
12901+
# 1680| getStmt(0): [ReturnStmt] return ...
12902+
# 1683| [TopLevelFunction] void captured_lambda(int, int&, int&&)
12903+
# 1683| <params>:
12904+
# 1683| getParameter(0): [Parameter] x
12905+
# 1683| Type = [IntType] int
12906+
# 1683| getParameter(1): [Parameter] y
12907+
# 1683| Type = [LValueReferenceType] int &
12908+
# 1683| getParameter(2): [Parameter] z
12909+
# 1683| Type = [RValueReferenceType] int &&
12910+
# 1684| getEntryPoint(): [BlockStmt] { ... }
12911+
# 1685| getStmt(0): [DeclStmt] declaration
12912+
# 1685| getDeclarationEntry(0): [VariableDeclarationEntry] definition of obj1
12913+
# 1685| Type = [LValueReferenceType] const CapturedLambdaMyObj &
12914+
# 1685| getVariable().getInitializer(): [Initializer] initializer for obj1
12915+
# 1685| getExpr(): [ConstructorCall] call to CapturedLambdaMyObj
12916+
# 1685| Type = [VoidType] void
12917+
# 1685| ValueCategory = prvalue
12918+
# 1685| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
12919+
# 1685| Type = [LValueReferenceType] const CapturedLambdaMyObj &
12920+
# 1685| ValueCategory = prvalue
12921+
# 1685| getExpr(): [CStyleCast] (const CapturedLambdaMyObj)...
12922+
# 1685| Conversion = [GlvalueConversion] glvalue conversion
12923+
# 1685| Type = [SpecifiedType] const CapturedLambdaMyObj
12924+
# 1685| ValueCategory = lvalue
12925+
# 1685| getExpr(): [TemporaryObjectExpr] temporary object
12926+
# 1685| Type = [Class] CapturedLambdaMyObj
12927+
# 1685| ValueCategory = lvalue
12928+
# 1686| getStmt(1): [DeclStmt] declaration
12929+
# 1686| getDeclarationEntry(0): [VariableDeclarationEntry] definition of obj2
12930+
# 1686| Type = [Class] CapturedLambdaMyObj
12931+
# 1686| getVariable().getInitializer(): [Initializer] initializer for obj2
12932+
# 1686| getExpr(): [ConstructorCall] call to CapturedLambdaMyObj
12933+
# 1686| Type = [VoidType] void
12934+
# 1686| ValueCategory = prvalue
12935+
# 1688| getStmt(2): [DeclStmt] declaration
12936+
# 1688| getDeclarationEntry(0): [VariableDeclarationEntry] definition of lambda_outer
12937+
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
12938+
# 1688| getVariable().getInitializer(): [Initializer] initializer for lambda_outer
12939+
# 1688| getExpr(): [LambdaExpression] [...](...){...}
12940+
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
12941+
# 1688| ValueCategory = prvalue
12942+
# 1688| getInitializer(): [ClassAggregateLiteral] {...}
12943+
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
12944+
# 1688| ValueCategory = prvalue
12945+
# 1688| getFieldExpr(obj1): [Literal] Unknown literal
12946+
# 1688| Type = [SpecifiedType] const CapturedLambdaMyObj
12947+
# 1688| ValueCategory = prvalue
12948+
# 1688| getFieldExpr(obj2): [Literal] Unknown literal
12949+
# 1688| Type = [Class] CapturedLambdaMyObj
12950+
# 1688| ValueCategory = prvalue
12951+
# 1688| getFieldExpr(x): [VariableAccess] x
12952+
# 1688| Type = [IntType] int
12953+
# 1688| ValueCategory = prvalue(load)
12954+
# 1688| getFieldExpr(y): [VariableAccess] y
12955+
# 1688| Type = [LValueReferenceType] int &
12956+
# 1688| ValueCategory = prvalue(load)
12957+
# 1688| getFieldExpr(z): [VariableAccess] z
12958+
# 1688| Type = [RValueReferenceType] int &&
12959+
# 1688| ValueCategory = prvalue(load)
12960+
# 1690| getFieldExpr(y).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
12961+
# 1690| Type = [IntType] int
12962+
# 1690| ValueCategory = prvalue(load)
12963+
# 1690| getFieldExpr(z).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
12964+
# 1690| Type = [IntType] int
12965+
# 1690| ValueCategory = prvalue(load)
12966+
# 1691| getStmt(3): [ReturnStmt] return ...
12967+
# 1688| [CopyAssignmentOperator] (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)& (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator=((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25) const&)
12968+
# 1688| <params>:
12969+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
12970+
#-----| Type = [LValueReferenceType] const lambda [] type at line 1688, col. 25 &
12971+
# 1688| [CopyConstructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25) const&)
12972+
# 1688| <params>:
12973+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
12974+
#-----| Type = [LValueReferenceType] const lambda [] type at line 1688, col. 25 &
12975+
# 1688| [MoveConstructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)&&)
12976+
# 1688| <params>:
12977+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
12978+
#-----| Type = [RValueReferenceType] lambda [] type at line 1688, col. 25 &&
12979+
# 1688| [Constructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)()
12980+
# 1688| <params>:
12981+
# 1688| [ConstMemberFunction] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const
12982+
# 1688| <params>:
12983+
# 1688| getEntryPoint(): [BlockStmt] { ... }
12984+
# 1689| getStmt(0): [DeclStmt] declaration
12985+
# 1689| getDeclarationEntry(0): [VariableDeclarationEntry] definition of lambda_inner
12986+
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
12987+
# 1689| getVariable().getInitializer(): [Initializer] initializer for lambda_inner
12988+
# 1689| getExpr(): [LambdaExpression] [...](...){...}
12989+
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
12990+
# 1689| ValueCategory = prvalue
12991+
# 1689| getInitializer(): [ClassAggregateLiteral] {...}
12992+
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
12993+
# 1689| ValueCategory = prvalue
12994+
# 1689| getFieldExpr(obj1): [Literal] Unknown literal
12995+
# 1689| Type = [SpecifiedType] const CapturedLambdaMyObj
12996+
# 1689| ValueCategory = prvalue
12997+
# 1689| getFieldExpr(obj2): [Literal] Unknown literal
12998+
# 1689| Type = [Class] CapturedLambdaMyObj
12999+
# 1689| ValueCategory = prvalue
13000+
# 1689| getFieldExpr(x): [PointerFieldAccess] x
13001+
# 1689| Type = [IntType] int
13002+
# 1689| ValueCategory = prvalue(load)
13003+
# 1689| getQualifier(): [ThisExpr] this
13004+
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
13005+
# 1689| ValueCategory = prvalue(load)
13006+
# 1689| getFieldExpr(y): [PointerFieldAccess] y
13007+
# 1689| Type = [IntType] int
13008+
# 1689| ValueCategory = prvalue(load)
13009+
# 1689| getQualifier(): [ThisExpr] this
13010+
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
13011+
# 1689| ValueCategory = prvalue(load)
13012+
# 1689| getFieldExpr(z): [PointerFieldAccess] z
13013+
# 1689| Type = [IntType] int
13014+
# 1689| ValueCategory = prvalue(load)
13015+
# 1689| getQualifier(): [ThisExpr] this
13016+
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
13017+
# 1689| ValueCategory = prvalue(load)
13018+
# 1690| getStmt(1): [ReturnStmt] return ...
13019+
# 1689| [CopyAssignmentOperator] (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)& (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator=((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29) const&)
13020+
# 1689| <params>:
13021+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
13022+
#-----| Type = [LValueReferenceType] const lambda [] type at line 1689, col. 29 &
13023+
# 1689| [CopyConstructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29) const&)
13024+
# 1689| <params>:
13025+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
13026+
#-----| Type = [LValueReferenceType] const lambda [] type at line 1689, col. 29 &
13027+
# 1689| [MoveConstructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)&&)
13028+
# 1689| <params>:
13029+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
13030+
#-----| Type = [RValueReferenceType] lambda [] type at line 1689, col. 29 &&
13031+
# 1689| [Constructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)()
13032+
# 1689| <params>:
13033+
# 1689| [ConstMemberFunction] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator()() const
13034+
# 1689| <params>:
13035+
# 1689| getEntryPoint(): [BlockStmt] { ... }
13036+
# 1689| getStmt(0): [EmptyStmt] ;
13037+
# 1689| getStmt(1): [ReturnStmt] return ...
1282313038
perf-regression.cpp:
1282413039
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
1282513040
# 4| <params>:

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ missingOperandType
66
duplicateChiOperand
77
sideEffectWithoutPrimary
88
instructionWithoutSuccessor
9+
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
10+
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
911
ambiguousSuccessors
1012
unexplainedLoop
1113
unnecessaryPhiInstruction

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ missingOperandType
66
duplicateChiOperand
77
sideEffectWithoutPrimary
88
instructionWithoutSuccessor
9+
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
10+
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
911
ambiguousSuccessors
1012
unexplainedLoop
1113
unnecessaryPhiInstruction

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,4 +1669,25 @@ void tuple_structured_binding_no_ref_get() {
16691669
}
16701670
}
16711671

1672+
void array_structured_binding_non_ref_init() {
1673+
int xs[2] = {1, 2};
1674+
auto [x0, x1] = xs;
1675+
}
1676+
1677+
class CapturedLambdaMyObj
1678+
{
1679+
public:
1680+
CapturedLambdaMyObj() {}
1681+
};
1682+
1683+
void captured_lambda(int x, int &y, int &&z)
1684+
{
1685+
const auto &obj1 = CapturedLambdaMyObj();
1686+
auto obj2 = CapturedLambdaMyObj();
1687+
1688+
auto lambda_outer = [obj1, obj2, x, y, z](){
1689+
auto lambda_inner = [obj1, obj2, x, y, z](){;};
1690+
};
1691+
}
1692+
16721693
// semmle-extractor-options: -std=c++17 --clang

0 commit comments

Comments
 (0)