Skip to content

Commit ce43802

Browse files
Handle suppressed move operations
1 parent 96e2ed0 commit ce43802

4 files changed

Lines changed: 95 additions & 45 deletions

File tree

cpp/misra/src/rules/RULE-15-0-1/AnalyzableClass.qll

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,38 @@ private predicate isMemberCustomized(MemberFunction f) {
1212
not f.isCompilerGenerated()
1313
}
1414

15+
private predicate isUserDeclared(MemberFunction f) { not f.isCompilerGenerated() }
16+
17+
/**
18+
* Holds if the implicit move constructor or move assignment operator of the class `c` will not be
19+
* declared.
20+
*
21+
* See [class.copy]/8 and [class.copy]
22+
*/
23+
private predicate implicitMoveIsSuppressed(Class c) {
24+
isUserDeclared(c.getAConstructor().(CopyConstructor))
25+
or
26+
isUserDeclared(c.getAConstructor().(CopyAssignmentOperator))
27+
or
28+
isUserDeclared(c.getDestructor())
29+
}
30+
31+
Constructor getMoveConstructor(Class c) {
32+
if
33+
not exists(MoveConstructor mc | mc = c.getAConstructor() and isUserDeclared(mc)) and
34+
implicitMoveIsSuppressed(c)
35+
then result = c.getAConstructor().(CopyConstructor)
36+
else result = c.getAConstructor().(MoveConstructor)
37+
}
38+
39+
Operator getMoveAssign(Class c) {
40+
if
41+
not exists(MoveAssignmentOperator mc | mc = c.getAMemberFunction() and isUserDeclared(mc)) and
42+
implicitMoveIsSuppressed(c)
43+
then result = c.getAMemberFunction().(CopyAssignmentOperator)
44+
else result = c.getAMemberFunction().(MoveAssignmentOperator)
45+
}
46+
1547
newtype TSpecialMember =
1648
TMoveConstructor() or
1749
TMoveAssignmentOperator() or
@@ -20,17 +52,19 @@ newtype TSpecialMember =
2052
TDestructor()
2153

2254
class AnalyzableClass extends Class {
23-
MoveConstructor moveCtor;
24-
MoveAssignmentOperator moveAssign;
2555
CopyConstructor copyCtor;
56+
// The move constructor may be suppressed, and the copy constructor may be used during moves.
57+
Constructor moveCtor;
2658
CopyAssignmentOperator copyAssign;
59+
// The move assignment operator may be suppressed, and the copy assignment operator may be used during moves.
60+
Operator moveAssign;
2761
Destructor dtor;
2862

2963
AnalyzableClass() {
30-
moveCtor = this.getAConstructor() and
3164
copyCtor = this.getAConstructor() and
32-
moveAssign = this.getAMemberFunction() and
65+
moveCtor = getMoveConstructor(this) and
3366
copyAssign = this.getAMemberFunction() and
67+
moveAssign = getMoveAssign(this) and
3468
dtor = this.getDestructor()
3569
}
3670

@@ -57,14 +91,22 @@ class AnalyzableClass extends Class {
5791
predicate destructible() { isUsable(dtor) }
5892

5993
predicate isCustomized(TSpecialMember s) {
60-
s instanceof TMoveConstructor and isMemberCustomized(moveCtor)
94+
s instanceof TMoveConstructor and
95+
isMemberCustomized(moveCtor) and
96+
declaresMoveConstructor()
6197
or
62-
s instanceof TMoveAssignmentOperator and isMemberCustomized(moveAssign)
98+
s instanceof TMoveAssignmentOperator and
99+
isMemberCustomized(moveAssign) and
100+
declaresMoveAssignmentOperator()
63101
or
64102
s instanceof TCopyConstructor and isMemberCustomized(copyCtor)
65103
or
66104
s instanceof TCopyAssignmentOperator and isMemberCustomized(copyAssign)
67105
or
68106
s instanceof TDestructor and isMemberCustomized(dtor)
69107
}
108+
109+
predicate declaresMoveConstructor() { not moveCtor = copyCtor }
110+
111+
predicate declaresMoveAssignmentOperator() { not moveAssign = copyAssign }
70112
}

cpp/misra/src/rules/RULE-15-0-1/ImproperlyProvidedSpecialMemberFunctions.ql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,29 @@ predicate violatesCustomizedMoveOrCopyRequirements(AnalyzableClass c, string rea
7979
)
8080
}
8181

82+
private predicate undeclaredMoveException(AnalyzableClass c) {
83+
// A copy-enabled class may have an undeclared move constructor.
84+
isCopyEnabled(c) and
85+
not c.moveAssignable() and
86+
not c.declaresMoveConstructor()
87+
or
88+
// A copy-assignable class may leave both move operations undeclared.
89+
isCopyEnabled(c) and
90+
c.moveAssignable() and
91+
not c.declaresMoveConstructor() and
92+
not c.declaresMoveAssignmentOperator()
93+
}
94+
8295
predicate violatesCustomizedDestructorRequirements(AnalyzableClass c, string reason) {
8396
c.isCustomized(TDestructor()) and
8497
(
8598
c.moveConstructible() and
8699
not c.isCustomized(TMoveConstructor()) and
100+
not undeclaredMoveException(c) and
87101
reason = "has customized the destructor, but does not customize the move constructor."
88102
or
89103
c.moveAssignable() and
104+
not undeclaredMoveException(c) and
90105
not c.isCustomized(TMoveAssignmentOperator()) and
91106
reason = "has customized the destructor, but does not customize the move assignment operator."
92107
or

cpp/misra/test/rules/RULE-15-0-1/ImproperlyProvidedSpecialMemberFunctions.expected

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,25 @@
1313
| test.cpp:115:7:115:21 | PrivateMoveCtor | Class 'PrivateMoveCtor' does not fall into a valid category (isUnmovable, move-only, or copy-enabled). |
1414
| test.cpp:128:7:128:23 | PrivateCopyAssign | Class 'PrivateCopyAssign' does not fall into a valid category (isUnmovable, move-only, or copy-enabled). |
1515
| test.cpp:141:7:141:23 | PrivateMoveAssign | Class 'PrivateMoveAssign' does not fall into a valid category (isUnmovable, move-only, or copy-enabled). |
16-
| test.cpp:181:7:181:45 | CustomizedCopyCtorDefaultedNonCompliant | Class 'CustomizedCopyCtorDefaultedNonCompliant' has customized copy constructor, but does not customize the destructor. |
17-
| test.cpp:188:7:188:43 | CustomizedCopyCtorDeletedNonCompliant | Class 'CustomizedCopyCtorDeletedNonCompliant' has customized copy constructor, but does not customize the destructor. |
18-
| test.cpp:194:7:194:36 | CustomizedMoveCtorNonCompliant | Class 'CustomizedMoveCtorNonCompliant' has customized move constructor, but does not customize the destructor. |
19-
| test.cpp:200:7:200:38 | CustomizedCopyAssignNonCompliant | Class 'CustomizedCopyAssignNonCompliant' has customized copy assignment operator, but does not customize the destructor. |
20-
| test.cpp:206:7:206:38 | CustomizedMoveAssignNonCompliant | Class 'CustomizedMoveAssignNonCompliant' has customized copy constructor, move assignment operator, move constructor, but does not customize the destructor. |
21-
| test.cpp:213:7:213:39 | MoveOnlyNotCustomizedNonCompliant | Class 'MoveOnlyNotCustomizedNonCompliant' has customized the destructor, but does not customize the move constructor. |
22-
| test.cpp:220:7:220:49 | MoveOnlyAssignableNotCustomizedNonCompliant | Class 'MoveOnlyAssignableNotCustomizedNonCompliant' has customized the destructor, but does not customize the move assignment operator. |
23-
| test.cpp:220:7:220:49 | MoveOnlyAssignableNotCustomizedNonCompliant | Class 'MoveOnlyAssignableNotCustomizedNonCompliant' has customized the destructor, but does not customize the move constructor. |
24-
| test.cpp:251:7:251:43 | CopyEnabledCustomizedDtorNonCompliant | Class 'CopyEnabledCustomizedDtorNonCompliant' has customized the destructor, but does not customize the copy assignment operator. |
25-
| test.cpp:251:7:251:43 | CopyEnabledCustomizedDtorNonCompliant | Class 'CopyEnabledCustomizedDtorNonCompliant' has customized the destructor, but does not customize the copy constructor. |
26-
| test.cpp:251:7:251:43 | CopyEnabledCustomizedDtorNonCompliant | Class 'CopyEnabledCustomizedDtorNonCompliant' has customized the destructor, but does not customize the move assignment operator. |
27-
| test.cpp:251:7:251:43 | CopyEnabledCustomizedDtorNonCompliant | Class 'CopyEnabledCustomizedDtorNonCompliant' has customized the destructor, but does not customize the move constructor. |
28-
| test.cpp:270:7:270:33 | UnmovableBaseNonvirtualDtor | Class 'UnmovableBaseNonvirtualDtor' violates inheritance requirements for special member functions. |
29-
| test.cpp:291:7:291:33 | UnmovablePrivateVirtualDtor | Class 'UnmovablePrivateVirtualDtor' violates inheritance requirements for special member functions. |
30-
| test.cpp:318:7:318:30 | BaseVirtualProtectedDtor | Class 'BaseVirtualProtectedDtor' violates inheritance requirements for special member functions. |
16+
| test.cpp:182:7:182:45 | CustomizedCopyCtorDefaultedNonCompliant | Class 'CustomizedCopyCtorDefaultedNonCompliant' has customized copy constructor, but does not customize the destructor. |
17+
| test.cpp:189:7:189:43 | CustomizedCopyCtorDeletedNonCompliant | Class 'CustomizedCopyCtorDeletedNonCompliant' has customized copy constructor, but does not customize the destructor. |
18+
| test.cpp:195:7:195:36 | CustomizedMoveCtorNonCompliant | Class 'CustomizedMoveCtorNonCompliant' has customized move constructor, but does not customize the destructor. |
19+
| test.cpp:201:7:201:38 | CustomizedCopyAssignNonCompliant | Class 'CustomizedCopyAssignNonCompliant' has customized copy assignment operator, but does not customize the destructor. |
20+
| test.cpp:207:7:207:38 | CustomizedMoveAssignNonCompliant | Class 'CustomizedMoveAssignNonCompliant' has customized copy constructor, move assignment operator, move constructor, but does not customize the destructor. |
21+
| test.cpp:214:7:214:39 | MoveOnlyNotCustomizedNonCompliant | Class 'MoveOnlyNotCustomizedNonCompliant' has customized the destructor, but does not customize the move constructor. |
22+
| test.cpp:223:7:223:49 | MoveOnlyAssignableNotCustomizedNonCompliant | Class 'MoveOnlyAssignableNotCustomizedNonCompliant' has customized the destructor, but does not customize the move assignment operator. |
23+
| test.cpp:223:7:223:49 | MoveOnlyAssignableNotCustomizedNonCompliant | Class 'MoveOnlyAssignableNotCustomizedNonCompliant' has customized the destructor, but does not customize the move constructor. |
24+
| test.cpp:258:7:258:43 | CopyEnabledCustomizedDtorNonCompliant | Class 'CopyEnabledCustomizedDtorNonCompliant' has customized the destructor, but does not customize the copy assignment operator. |
25+
| test.cpp:258:7:258:43 | CopyEnabledCustomizedDtorNonCompliant | Class 'CopyEnabledCustomizedDtorNonCompliant' has customized the destructor, but does not customize the copy constructor. |
26+
| test.cpp:258:7:258:43 | CopyEnabledCustomizedDtorNonCompliant | Class 'CopyEnabledCustomizedDtorNonCompliant' has customized the destructor, but does not customize the move assignment operator. |
27+
| test.cpp:258:7:258:43 | CopyEnabledCustomizedDtorNonCompliant | Class 'CopyEnabledCustomizedDtorNonCompliant' has customized the destructor, but does not customize the move constructor. |
28+
| test.cpp:307:7:307:47 | CopyAssignableCustomizedDtorNonCompliant1 | Class 'CopyAssignableCustomizedDtorNonCompliant1' has customized the destructor, but does not customize the move assignment operator. |
29+
| test.cpp:317:7:317:47 | CopyAssignableCustomizedDtorNonCompliant2 | Class 'CopyAssignableCustomizedDtorNonCompliant2' has customized the destructor, but does not customize the move constructor. |
30+
| test.cpp:327:7:327:47 | CopyAssignableCustomizedDtorNonCompliant3 | Class 'CopyAssignableCustomizedDtorNonCompliant3' does not fall into a valid category (isUnmovable, move-only, or copy-enabled). |
31+
| test.cpp:337:7:337:47 | CopyAssignableCustomizedDtorNonCompliant4 | Class 'CopyAssignableCustomizedDtorNonCompliant4' has customized the destructor, but does not customize the move assignment operator. |
32+
| test.cpp:337:7:337:47 | CopyAssignableCustomizedDtorNonCompliant4 | Class 'CopyAssignableCustomizedDtorNonCompliant4' has customized the destructor, but does not customize the move constructor. |
33+
| test.cpp:347:7:347:47 | CopyAssignableCustomizedDtorNonCompliant5 | Class 'CopyAssignableCustomizedDtorNonCompliant5' has customized the destructor, but does not customize the move assignment operator. |
34+
| test.cpp:347:7:347:47 | CopyAssignableCustomizedDtorNonCompliant5 | Class 'CopyAssignableCustomizedDtorNonCompliant5' has customized the destructor, but does not customize the move constructor. |
35+
| test.cpp:357:7:357:33 | UnmovableBaseNonvirtualDtor | Class 'UnmovableBaseNonvirtualDtor' violates inheritance requirements for special member functions. |
36+
| test.cpp:378:7:378:33 | UnmovablePrivateVirtualDtor | Class 'UnmovablePrivateVirtualDtor' violates inheritance requirements for special member functions. |
37+
| test.cpp:405:7:405:30 | BaseVirtualProtectedDtor | Class 'BaseVirtualProtectedDtor' violates inheritance requirements for special member functions. |

cpp/misra/test/rules/RULE-15-0-1/test.cpp

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ class CopyEnabledCustomizedDtorCompliant1 { // COMPLIANT: copy-enabled (2)
273273
CUSTOMIZED, CUSTOMIZED, CUSTOMIZED, CUSTOMIZED)
274274
};
275275

276-
class CopyEnabledCustomizedDtorCompliant2 { // NON-COMPLIANT: copy-enabled (2)
276+
class CopyEnabledCustomizedDtorCompliant2 { // COMPLIANT: copy-enabled (2)
277277
public:
278278
COPY_CTOR(CopyEnabledCustomizedDtorCompliant2) CUSTOMIZED;
279279
// No move constructor declared
@@ -296,7 +296,7 @@ class CopyAssignableCustomizedDtorCompliant1 { // COMPLIANT
296296
// copy-assignable class with both move operations not declared
297297
class CopyAssignableCustomizedDtorCompliant2 { // COMPLIANT
298298
public:
299-
COPY_CTOR(CopyAssignableCustomizedDtorCompliant2) DEFAULTED;
299+
COPY_CTOR(CopyAssignableCustomizedDtorCompliant2) CUSTOMIZED;
300300
// Move constructor is not declared
301301
COPY_ASSIGN(CopyAssignableCustomizedDtorCompliant2) CUSTOMIZED;
302302
// Move assignment operator is not declared
@@ -306,8 +306,8 @@ class CopyAssignableCustomizedDtorCompliant2 { // COMPLIANT
306306
// copy-assignable class with only one of move operations not declared
307307
class CopyAssignableCustomizedDtorNonCompliant1 { // NON_COMPLIANT
308308
public:
309-
COPY_CTOR(CopyAssignableCustomizedDtorNonCompliant1)
310-
CUSTOMIZED MOVE_CTOR(CopyAssignableCustomizedDtorNonCompliant1) CUSTOMIZED;
309+
COPY_CTOR(CopyAssignableCustomizedDtorNonCompliant1) CUSTOMIZED;
310+
MOVE_CTOR(CopyAssignableCustomizedDtorNonCompliant1) CUSTOMIZED;
311311
COPY_ASSIGN(CopyAssignableCustomizedDtorNonCompliant1) CUSTOMIZED;
312312
// Move assignment operator is not declared
313313
DTOR(CopyAssignableCustomizedDtorNonCompliant1) CUSTOMIZED;
@@ -323,7 +323,7 @@ class CopyAssignableCustomizedDtorNonCompliant2 { // NON_COMPLIANT
323323
DTOR(CopyAssignableCustomizedDtorNonCompliant2) CUSTOMIZED;
324324
};
325325

326-
// copy-assignable class with only one of move operations not declared
326+
// copy-assignable class with only a copy operation not declared
327327
class CopyAssignableCustomizedDtorNonCompliant3 { // NON_COMPLIANT
328328
public:
329329
COPY_CTOR(CopyAssignableCustomizedDtorNonCompliant3) CUSTOMIZED;
@@ -337,32 +337,22 @@ class CopyAssignableCustomizedDtorNonCompliant3 { // NON_COMPLIANT
337337
class CopyAssignableCustomizedDtorNonCompliant4 { // NON_COMPLIANT
338338
public:
339339
COPY_CTOR(CopyAssignableCustomizedDtorNonCompliant4) CUSTOMIZED;
340-
// Move constructor is not declared
340+
MOVE_CTOR(CopyAssignableCustomizedDtorNonCompliant4) DEFAULTED;
341341
COPY_ASSIGN(CopyAssignableCustomizedDtorNonCompliant4) CUSTOMIZED;
342-
MOVE_ASSIGN(CopyAssignableCustomizedDtorNonCompliant4) CUSTOMIZED;
343-
DTOR(CopyAssignableCustomizedDtorNonCompliant4) CUSTOMIZED
342+
// Move assignment operator is not declared
343+
DTOR(CopyAssignableCustomizedDtorNonCompliant4) CUSTOMIZED;
344344
};
345345

346346
// copy-assignable class with only one of move operations not declared
347347
class CopyAssignableCustomizedDtorNonCompliant5 { // NON_COMPLIANT
348348
public:
349349
COPY_CTOR(CopyAssignableCustomizedDtorNonCompliant5) CUSTOMIZED;
350-
MOVE_CTOR(CopyAssignableCustomizedDtorNonCompliant5) DEFAULTED;
350+
// Move constructor is not declared
351351
COPY_ASSIGN(CopyAssignableCustomizedDtorNonCompliant5) CUSTOMIZED;
352-
// Move assignment operator is not declared
352+
MOVE_ASSIGN(CopyAssignableCustomizedDtorNonCompliant5) DEFAULTED;
353353
DTOR(CopyAssignableCustomizedDtorNonCompliant5) CUSTOMIZED;
354354
};
355355

356-
// copy-assignable class with only one of move operations not declared
357-
class CopyAssignableCustomizedDtorNonCompliant6 { // NON_COMPLIANT
358-
public:
359-
COPY_CTOR(CopyAssignableCustomizedDtorNonCompliant6) CUSTOMIZED;
360-
// Move constructor is not declared
361-
COPY_ASSIGN(CopyAssignableCustomizedDtorNonCompliant6) CUSTOMIZED;
362-
MOVE_ASSIGN(CopyAssignableCustomizedDtorNonCompliant6) DEFAULTED;
363-
DTOR(CopyAssignableCustomizedDtorNonCompliant6) CUSTOMIZED;
364-
};
365-
366356
// A public unmovable base class shall have a public virtual destructor
367357
class UnmovableBaseNonvirtualDtor { // NON_COMPLIANT
368358
public:
@@ -447,10 +437,6 @@ class NonTrivialClass { // NON_COMPLIANT - audit result
447437
int y;
448438

449439
public:
450-
COPY_CTOR(NonTrivialClass) {
451-
x = 1;
452-
y = 2;
453-
}
454440
~NonTrivialClass() { x = 1; }
455441
};
456442

0 commit comments

Comments
 (0)