diff --git a/change_notes/2026-10-20-fix-fp-rule-15-1-4-template-constructors.md b/change_notes/2026-10-20-fix-fp-rule-15-1-4-template-constructors.md new file mode 100644 index 000000000..8c449bbb8 --- /dev/null +++ b/change_notes/2026-10-20-fix-fp-rule-15-1-4-template-constructors.md @@ -0,0 +1,2 @@ +- `RULE-15-1-4` - `NonStaticMemberNotInitBeforeUse.ql`: + - Remove false positives for constructors of uninstantiated class templates, where delegating constructors are not modelled as such. The instantiations are still checked. diff --git a/cpp/misra/src/rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.ql b/cpp/misra/src/rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.ql index 806281b7b..434febcd6 100644 --- a/cpp/misra/src/rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.ql +++ b/cpp/misra/src/rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.ql @@ -116,6 +116,9 @@ class IncompleteConstructor extends Constructor, IncompleteInitialization { not getDeclaringType() instanceof Union and this.getDeclaringType().hasDefinition() and not this.isDeleted() and + // Constructors of uninstantiated class templates cannot be analysed reliably, because for + // instance a delegating constructor is not modelled as such. The instantiations are checked. + not this.getDeclaringType() instanceof TemplateClass and // Delegating constructors do not need to initialize members not any(ConstructorDelegationInit init) = this.getAnInitializer() and // exclude defaulted move and copy constructors. diff --git a/cpp/misra/test/rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.expected b/cpp/misra/test/rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.expected index 18c4851f7..f25a06842 100644 --- a/cpp/misra/test/rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.expected +++ b/cpp/misra/test/rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.expected @@ -24,3 +24,4 @@ | test.cpp:267:18:267:18 | a | Aggregate variable does not initialize non-static data member $@ (and 9 more). | test.cpp:262:43:262:45 | m10 | m10 | | test.cpp:290:18:290:18 | a | Aggregate variable does not initialize non-static data member $@ (and 1 more). | test.cpp:285:9:285:10 | m1 | m1 | | test.cpp:290:18:290:18 | a | Aggregate variable does not initialize non-static data member $@ (and 1 more). | test.cpp:286:11:286:12 | m2 | m2 | +| test.cpp:318:3:318:3 | TemplateMemberUninit | Constructor does not initialize non-static data member $@. | test.cpp:322:7:322:8 | m2 | m2 | diff --git a/cpp/misra/test/rules/RULE-15-1-4/test.cpp b/cpp/misra/test/rules/RULE-15-1-4/test.cpp index 39aa14a49..ef099e566 100644 --- a/cpp/misra/test/rules/RULE-15-1-4/test.cpp +++ b/cpp/misra/test/rules/RULE-15-1-4/test.cpp @@ -302,4 +302,52 @@ union UnionWithConstructor { // Union constructors should still be required to initialize one member, but // this is not implemented. UnionWithConstructor() {} // NON_COMPLIANT[False negative] -}; \ No newline at end of file +}; +template class TemplateAllInit { +public: + TemplateAllInit(T value) : m1(value), m2(0) {} // COMPLIANT + TemplateAllInit(const TemplateAllInit &) = delete; + +private: + T m1; + int m2; +}; + +template class TemplateMemberUninit { +public: + TemplateMemberUninit(T value) : m1(value) {} // NON_COMPLIANT + +private: + T m1; + int m2; +}; + +template class TemplateOutOfLineInit { +public: + TemplateOutOfLineInit(T value); + +private: + T m1; + int m2; +}; + +template +TemplateOutOfLineInit::TemplateOutOfLineInit(T value) + : m1(value), m2(0) {} // COMPLIANT + +template class TemplateDelegating { +public: + TemplateDelegating() : TemplateDelegating(0) {} // COMPLIANT + TemplateDelegating(T value) : m1(value), m2(0) {} // COMPLIANT + +private: + T m1; + int m2; +}; + +void instantiateTemplates() { + TemplateAllInit a(1); + TemplateMemberUninit b(1); + TemplateOutOfLineInit c(1); + TemplateDelegating d; +}