diff --git a/cpp/ql/lib/change-notes/2022-03-10-template-implicit-copy.md b/cpp/ql/lib/change-notes/2022-03-10-template-implicit-copy.md new file mode 100644 index 00000000000..fe2afba6568 --- /dev/null +++ b/cpp/ql/lib/change-notes/2022-03-10-template-implicit-copy.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates. \ No newline at end of file diff --git a/cpp/ql/lib/semmle/code/cpp/Class.qll b/cpp/ql/lib/semmle/code/cpp/Class.qll index b15d41a37fb..a91cedb9a0b 100644 --- a/cpp/ql/lib/semmle/code/cpp/Class.qll +++ b/cpp/ql/lib/semmle/code/cpp/Class.qll @@ -251,6 +251,16 @@ class Class extends UserType { not this.implicitCopyConstructorDeleted() and forall(CopyConstructor cc | cc = this.getAMemberFunction() | cc.isCompilerGenerated() and not cc.isDeleted() + ) and + ( + not this instanceof ClassTemplateInstantiation + or + this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyConstructor() + ) and + ( + not this instanceof PartialClassTemplateSpecialization + or + this.(PartialClassTemplateSpecialization).getPrimaryTemplate().hasImplicitCopyConstructor() ) } @@ -266,6 +276,18 @@ class Class extends UserType { not this.implicitCopyAssignmentOperatorDeleted() and forall(CopyAssignmentOperator ca | ca = this.getAMemberFunction() | ca.isCompilerGenerated() and not ca.isDeleted() + ) and + ( + not this instanceof ClassTemplateInstantiation + or + this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyAssignmentOperator() + ) and + ( + not this instanceof PartialClassTemplateSpecialization + or + this.(PartialClassTemplateSpecialization) + .getPrimaryTemplate() + .hasImplicitCopyAssignmentOperator() ) } diff --git a/cpp/ql/test/library-tests/special_members/generated_copy/assign.expected b/cpp/ql/test/library-tests/special_members/generated_copy/assign.expected index eec36e7e39c..28c90cb5233 100644 --- a/cpp/ql/test/library-tests/special_members/generated_copy/assign.expected +++ b/cpp/ql/test/library-tests/special_members/generated_copy/assign.expected @@ -11,6 +11,7 @@ | difference::Base | can | does NOT | have implicit copy assignment | | difference::OnlyAssign | can | does | have implicit copy assignment | | difference::OnlyCtor | can NOT | does NOT | have implicit copy assignment | +| instantiated_explicit_ctor::Wrapper | can | does | have implicit copy assignment | | moves::MoveAssign | can NOT | does NOT | have implicit copy assignment | | moves::MoveCtor | can NOT | does NOT | have implicit copy assignment | | private_cc::C | can | does NOT | have implicit copy assignment | diff --git a/cpp/ql/test/library-tests/special_members/generated_copy/copy.cpp b/cpp/ql/test/library-tests/special_members/generated_copy/copy.cpp index 8d68cfdc09e..fac52670bca 100644 --- a/cpp/ql/test/library-tests/special_members/generated_copy/copy.cpp +++ b/cpp/ql/test/library-tests/special_members/generated_copy/copy.cpp @@ -131,3 +131,21 @@ namespace difference { class OnlyAssign : Base { }; } + +namespace instantiated_explicit_ctor { + template + class Wrapper { + public: + Wrapper(Wrapper &other) { + m_t = other.m_t; + } + + Wrapper() { + m_t = 0; + } + private: + T m_t; + }; + + Wrapper wrapped_int; +} diff --git a/cpp/ql/test/library-tests/special_members/generated_copy/ctor.expected b/cpp/ql/test/library-tests/special_members/generated_copy/ctor.expected index 22745978bf8..90a3f811e5d 100644 --- a/cpp/ql/test/library-tests/special_members/generated_copy/ctor.expected +++ b/cpp/ql/test/library-tests/special_members/generated_copy/ctor.expected @@ -11,6 +11,7 @@ | difference::Base | can | does NOT | have implicit copy constructor | | difference::OnlyAssign | can NOT | does NOT | have implicit copy constructor | | difference::OnlyCtor | can | does | have implicit copy constructor | +| instantiated_explicit_ctor::Wrapper | can | does NOT | have implicit copy constructor | | moves::MoveAssign | can NOT | does NOT | have implicit copy constructor | | moves::MoveCtor | can NOT | does NOT | have implicit copy constructor | | private_cc::C | can | does NOT | have implicit copy constructor | diff --git a/cpp/ql/test/library-tests/special_members/generated_copy/functions.expected b/cpp/ql/test/library-tests/special_members/generated_copy/functions.expected index 22282641b37..434b950e35c 100644 --- a/cpp/ql/test/library-tests/special_members/generated_copy/functions.expected +++ b/cpp/ql/test/library-tests/special_members/generated_copy/functions.expected @@ -86,5 +86,9 @@ | copy.cpp:131:9:131:9 | OnlyAssign | deleted | | | copy.cpp:131:9:131:9 | operator= | | | | copy.cpp:131:9:131:9 | operator= | | | +| copy.cpp:137:9:137:9 | operator= | | | +| copy.cpp:139:5:139:11 | Wrapper | | | +| copy.cpp:143:5:143:5 | Wrapper | | | +| copy.cpp:143:5:143:11 | Wrapper | | | | file://:0:0:0:0 | operator= | | | | file://:0:0:0:0 | operator= | | |