C++: test for destructors in range-based for

This commit is contained in:
Robert Marsh
2024-02-01 20:47:20 +00:00
parent 820f4a5571
commit 4513fd1b52
3 changed files with 191 additions and 14 deletions

View File

@@ -9384,14 +9384,30 @@ ir.cpp:
# 1054| getRightOperand().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1054| Type = [IntType] int
# 1054| ValueCategory = prvalue(load)
# 1059| [CopyAssignmentOperator] vector<String>& vector<String>::operator=(vector<String> const&)
# 1059| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const vector<String> &
# 1059| [CopyAssignmentOperator] vector<int>& vector<int>::operator=(vector<int> const&)
# 1059| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const vector<int> &
# 1059| [MoveAssignmentOperator] vector<int>& vector<int>::operator=(vector<int>&&)
# 1059| [CopyConstructor] void vector<String>::vector(vector<String> const&)
# 1059| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] vector<int> &&
#-----| Type = [LValueReferenceType] const vector<String> &
# 1059| [CopyConstructor] void vector<int>::vector(vector<int> const&)
# 1059| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const vector<int> &
# 1060| [CopyAssignmentOperator] vector<String>::iterator& vector<String>::iterator::operator=(vector<String>::iterator const public&)
# 1060| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const iterator &
# 1060| [MoveAssignmentOperator] vector<String>::iterator& vector<String>::iterator::operator=(vector<String>::iterator&&)
# 1060| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] iterator &&
# 1060| [CopyAssignmentOperator] vector<int>::iterator& vector<int>::iterator::operator=(vector<int>::iterator const public&)
# 1060| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -9400,14 +9416,22 @@ ir.cpp:
# 1060| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] iterator &&
# 1062| [MemberFunction] vector<String>::iterator& vector<String>::iterator::operator++()
# 1062| <params>:
# 1062| [MemberFunction] vector<T>::iterator& vector<T>::iterator::operator++()
# 1062| <params>:
# 1062| [MemberFunction] vector<int>::iterator& vector<int>::iterator::operator++()
# 1062| <params>:
# 1063| [ConstMemberFunction] String& vector<String>::iterator::operator*() const
# 1063| <params>:
# 1063| [ConstMemberFunction] T& vector<T>::iterator::operator*() const
# 1063| <params>:
# 1063| [ConstMemberFunction] int& vector<int>::iterator::operator*() const
# 1063| <params>:
# 1065| [ConstMemberFunction] bool vector<String>::iterator::operator!=(vector<String>::iterator) const
# 1065| <params>:
# 1065| getParameter(0): [Parameter] right
# 1065| Type = [NestedStruct] iterator
# 1065| [ConstMemberFunction] bool vector<T>::iterator::operator!=(vector<T>::iterator) const
# 1065| <params>:
# 1065| getParameter(0): [Parameter] right
@@ -9416,10 +9440,24 @@ ir.cpp:
# 1065| <params>:
# 1065| getParameter(0): [Parameter] right
# 1065| Type = [NestedStruct] iterator
# 1067| [Constructor] void vector<String>::vector(String)
# 1067| <params>:
# 1067| getParameter(0): [Parameter] (unnamed parameter 0)
# 1067| Type = [Struct] String
# 1067| [Constructor] void vector<T>::vector(T)
# 1067| <params>:
# 1067| getParameter(0): [Parameter] (unnamed parameter 0)
# 1067| Type = [TemplateParameter] T
# 1067| [Destructor] void vector<T>::~vector()
# 1067| <params>:
# 1068| [ConstMemberFunction] vector<String>::iterator vector<String>::begin() const
# 1068| <params>:
# 1068| [ConstMemberFunction] vector<T>::iterator vector<T>::begin() const
# 1068| <params>:
# 1068| [ConstMemberFunction] vector<int>::iterator vector<int>::begin() const
# 1068| <params>:
# 1069| [ConstMemberFunction] vector<String>::iterator vector<String>::end() const
# 1069| <params>:
# 1069| [ConstMemberFunction] vector<T>::iterator vector<T>::end() const
# 1069| <params>:
# 1069| [ConstMemberFunction] vector<int>::iterator vector<int>::end() const
@@ -16346,7 +16384,47 @@ ir.cpp:
# 2145| getQualifier(): [VariableAccess] s
# 2145| Type = [Struct] String
# 2145| ValueCategory = lvalue
# 2148| getStmt(2): [ReturnStmt] return ...
# 2149| getStmt(2): [RangeBasedForStmt] for(...:...) ...
# 2149| getChild(0): [DeclStmt] declaration
# 2149| getBeginEndDeclaration(): [DeclStmt] declaration
# 2149| getCondition(): [FunctionCall] call to operator!=
# 2149| Type = [BoolType] bool
# 2149| ValueCategory = prvalue
# 2149| getQualifier(): [VariableAccess] (__begin)
# 2149| Type = [NestedStruct] iterator
# 2149| ValueCategory = lvalue
# 2149| getArgument(0): [VariableAccess] (__end)
# 2149| Type = [NestedStruct] iterator
# 2149| ValueCategory = prvalue(load)
#-----| getQualifier().getFullyConverted(): [CStyleCast] (const iterator)...
#-----| Conversion = [GlvalueConversion] glvalue conversion
#-----| Type = [SpecifiedType] const iterator
#-----| ValueCategory = lvalue
# 2149| getUpdate(): [FunctionCall] call to operator++
# 2149| Type = [LValueReferenceType] iterator &
# 2149| ValueCategory = prvalue
# 2149| getQualifier(): [VariableAccess] (__begin)
# 2149| Type = [NestedStruct] iterator
# 2149| ValueCategory = lvalue
# 2149| getChild(4): [DeclStmt] declaration
# 2149| getStmt(): [BlockStmt] { ... }
# 2150| getStmt(0): [DeclStmt] declaration
# 2150| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s2
# 2150| Type = [Struct] String
# 2150| getVariable().getInitializer(): [Initializer] initializer for s2
# 2150| getExpr(): [ConstructorCall] call to String
# 2150| Type = [VoidType] void
# 2150| ValueCategory = prvalue
# 2151| getImplicitDestructorCall(0): [DestructorCall] call to ~String
# 2151| Type = [VoidType] void
# 2151| ValueCategory = prvalue
# 2151| getQualifier(): [VariableAccess] s2
# 2151| Type = [Struct] String
# 2151| ValueCategory = lvalue
# 2149| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2149| Type = [NestedStruct] iterator
# 2149| ValueCategory = lvalue
# 2152| getStmt(3): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -1064,7 +1064,7 @@ struct vector {
bool operator!=(iterator right) const;
};
vector(T); ~vector();
iterator begin() const;
iterator end() const;
};
@@ -2145,6 +2145,12 @@ void ForDestructors() {
for(String s("hello"); c != 0; c = s.pop_back()) {
String s2;
}
for(String s : vector<String>(String("hello"))) {
String s2;
}
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -12080,16 +12080,109 @@ ir.cpp:
#-----| Goto (back edge) -> Block 1
# 2145| Block 3
# 2145| r2145_24(glval<String>) = VariableAddress[s] :
# 2145| r2145_25(glval<unknown>) = FunctionAddress[~String] :
# 2145| v2145_26(void) = Call[~String] : func:r2145_25, this:r2145_24
# 2145| mu2145_27(unknown) = ^CallSideEffect : ~m?
# 2145| v2145_28(void) = ^IndirectReadSideEffect[-1] : &:r2145_24, ~m?
# 2145| mu2145_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r2145_24
# 2148| v2148_1(void) = NoOp :
# 2143| v2143_4(void) = ReturnVoid :
# 2143| v2143_5(void) = AliasedUse : ~m?
# 2143| v2143_6(void) = ExitFunction :
# 2145| r2145_24(glval<String>) = VariableAddress[s] :
# 2145| r2145_25(glval<unknown>) = FunctionAddress[~String] :
# 2145| v2145_26(void) = Call[~String] : func:r2145_25, this:r2145_24
# 2145| mu2145_27(unknown) = ^CallSideEffect : ~m?
# 2145| v2145_28(void) = ^IndirectReadSideEffect[-1] : &:r2145_24, ~m?
# 2145| mu2145_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r2145_24
# 2149| r2149_1(glval<vector<String> &&>) = VariableAddress[(__range)] :
# 2149| r2149_2(glval<vector<String>>) = VariableAddress[#temp2149:20] :
# 2149| mu2149_3(vector<String>) = Uninitialized[#temp2149:20] : &:r2149_2
# 2149| r2149_4(glval<unknown>) = FunctionAddress[vector] :
# 2149| r2149_5(glval<String>) = VariableAddress[#temp2149:35] :
# 2149| mu2149_6(String) = Uninitialized[#temp2149:35] : &:r2149_5
# 2149| r2149_7(glval<unknown>) = FunctionAddress[String] :
# 2149| r2149_8(glval<char[6]>) = StringConstant["hello"] :
# 2149| r2149_9(char *) = Convert : r2149_8
# 2149| v2149_10(void) = Call[String] : func:r2149_7, this:r2149_5, 0:r2149_9
# 2149| mu2149_11(unknown) = ^CallSideEffect : ~m?
# 2149| v2149_12(void) = ^BufferReadSideEffect[0] : &:r2149_9, ~m?
# 2149| mu2149_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r2149_5
# 2149| r2149_14(String) = Load[#temp2149:35] : &:r2149_5, ~m?
# 2149| v2149_15(void) = Call[vector] : func:r2149_4, this:r2149_2, 0:r2149_14
# 2149| mu2149_16(unknown) = ^CallSideEffect : ~m?
# 2149| mu2149_17(vector<String>) = ^IndirectMayWriteSideEffect[-1] : &:r2149_2
# 2149| r2149_18(vector<String> &) = CopyValue : r2149_2
# 2149| mu2149_19(vector<String> &&) = Store[(__range)] : &:r2149_1, r2149_18
# 2149| r2149_20(glval<iterator>) = VariableAddress[(__begin)] :
# 2149| r2149_21(glval<vector<String> &&>) = VariableAddress[(__range)] :
# 2149| r2149_22(vector<String> &&) = Load[(__range)] : &:r2149_21, ~m?
#-----| r0_1(glval<vector<String>>) = CopyValue : r2149_22
#-----| r0_2(glval<vector<String>>) = Convert : r0_1
# 2149| r2149_23(glval<unknown>) = FunctionAddress[begin] :
# 2149| r2149_24(iterator) = Call[begin] : func:r2149_23, this:r0_2
# 2149| mu2149_25(unknown) = ^CallSideEffect : ~m?
#-----| v0_3(void) = ^IndirectReadSideEffect[-1] : &:r0_2, ~m?
# 2149| mu2149_26(iterator) = Store[(__begin)] : &:r2149_20, r2149_24
# 2149| r2149_27(glval<iterator>) = VariableAddress[(__end)] :
# 2149| r2149_28(glval<vector<String> &&>) = VariableAddress[(__range)] :
# 2149| r2149_29(vector<String> &&) = Load[(__range)] : &:r2149_28, ~m?
#-----| r0_4(glval<vector<String>>) = CopyValue : r2149_29
#-----| r0_5(glval<vector<String>>) = Convert : r0_4
# 2149| r2149_30(glval<unknown>) = FunctionAddress[end] :
# 2149| r2149_31(iterator) = Call[end] : func:r2149_30, this:r0_5
# 2149| mu2149_32(unknown) = ^CallSideEffect : ~m?
#-----| v0_6(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m?
# 2149| mu2149_33(iterator) = Store[(__end)] : &:r2149_27, r2149_31
#-----| Goto -> Block 4
# 2149| Block 4
# 2149| r2149_34(glval<iterator>) = VariableAddress[(__begin)] :
#-----| r0_7(glval<iterator>) = Convert : r2149_34
# 2149| r2149_35(glval<unknown>) = FunctionAddress[operator!=] :
# 2149| r2149_36(glval<iterator>) = VariableAddress[(__end)] :
# 2149| r2149_37(iterator) = Load[(__end)] : &:r2149_36, ~m?
# 2149| r2149_38(bool) = Call[operator!=] : func:r2149_35, this:r0_7, 0:r2149_37
# 2149| mu2149_39(unknown) = ^CallSideEffect : ~m?
#-----| v0_8(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m?
# 2149| v2149_40(void) = ConditionalBranch : r2149_38
#-----| False -> Block 6
#-----| True -> Block 5
# 2149| Block 5
# 2149| r2149_41(glval<String>) = VariableAddress[s] :
# 2149| mu2149_42(String) = Uninitialized[s] : &:r2149_41
# 2149| r2149_43(glval<unknown>) = FunctionAddress[String] :
# 2149| r2149_44(glval<iterator>) = VariableAddress[(__begin)] :
#-----| r0_9(glval<iterator>) = Convert : r2149_44
# 2149| r2149_45(glval<unknown>) = FunctionAddress[operator*] :
# 2149| r2149_46(String &) = Call[operator*] : func:r2149_45, this:r0_9
# 2149| mu2149_47(unknown) = ^CallSideEffect : ~m?
#-----| v0_10(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~m?
# 2149| r2149_48(glval<String>) = CopyValue : r2149_46
# 2149| r2149_49(glval<String>) = Convert : r2149_48
# 2149| r2149_50(String &) = CopyValue : r2149_49
# 2149| v2149_51(void) = Call[String] : func:r2149_43, this:r2149_41, 0:r2149_50
# 2149| mu2149_52(unknown) = ^CallSideEffect : ~m?
# 2149| v2149_53(void) = ^BufferReadSideEffect[0] : &:r2149_50, ~m?
# 2149| mu2149_54(String) = ^IndirectMayWriteSideEffect[-1] : &:r2149_41
# 2150| r2150_1(glval<String>) = VariableAddress[s2] :
# 2150| mu2150_2(String) = Uninitialized[s2] : &:r2150_1
# 2150| r2150_3(glval<unknown>) = FunctionAddress[String] :
# 2150| v2150_4(void) = Call[String] : func:r2150_3, this:r2150_1
# 2150| mu2150_5(unknown) = ^CallSideEffect : ~m?
# 2150| mu2150_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r2150_1
# 2151| r2151_1(glval<String>) = VariableAddress[s2] :
# 2151| r2151_2(glval<unknown>) = FunctionAddress[~String] :
# 2151| v2151_3(void) = Call[~String] : func:r2151_2, this:r2151_1
# 2151| mu2151_4(unknown) = ^CallSideEffect : ~m?
# 2151| v2151_5(void) = ^IndirectReadSideEffect[-1] : &:r2151_1, ~m?
# 2151| mu2151_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r2151_1
# 2149| r2149_55(glval<iterator>) = VariableAddress[(__begin)] :
# 2149| r2149_56(glval<unknown>) = FunctionAddress[operator++] :
# 2149| r2149_57(iterator &) = Call[operator++] : func:r2149_56, this:r2149_55
# 2149| mu2149_58(unknown) = ^CallSideEffect : ~m?
# 2149| v2149_59(void) = ^IndirectReadSideEffect[-1] : &:r2149_55, ~m?
# 2149| mu2149_60(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r2149_55
# 2149| r2149_61(glval<iterator>) = CopyValue : r2149_57
#-----| Goto (back edge) -> Block 4
# 2152| Block 6
# 2152| v2152_1(void) = NoOp :
# 2143| v2143_4(void) = ReturnVoid :
# 2143| v2143_5(void) = AliasedUse : ~m?
# 2143| v2143_6(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()