-
Notifications
You must be signed in to change notification settings - Fork 75
Implement Preconditions2, appropriate types sent via ellipsis. #1123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
MichaelRFairhurst
merged 3 commits into
main
from
michaelrfairhurst/preconditions-rule-8-2-11-types-passed-by-ellipsis
Apr 30, 2026
Merged
Changes from 2 commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
cpp/common/src/codingstandards/cpp/exclusions/cpp/Preconditions2.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| //** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ | ||
| import cpp | ||
| import RuleMetadata | ||
| import codingstandards.cpp.exclusions.RuleMetadata | ||
|
|
||
| newtype Preconditions2Query = TInappropriateArgumentTypePassedViaEllipsisQuery() | ||
|
|
||
| predicate isPreconditions2QueryMetadata(Query query, string queryId, string ruleId, string category) { | ||
| query = | ||
| // `Query` instance for the `inappropriateArgumentTypePassedViaEllipsis` query | ||
| Preconditions2Package::inappropriateArgumentTypePassedViaEllipsisQuery() and | ||
| queryId = | ||
| // `@id` for the `inappropriateArgumentTypePassedViaEllipsis` query | ||
| "cpp/misra/inappropriate-argument-type-passed-via-ellipsis" and | ||
| ruleId = "RULE-8-2-11" and | ||
| category = "required" | ||
| } | ||
|
|
||
| module Preconditions2Package { | ||
| Query inappropriateArgumentTypePassedViaEllipsisQuery() { | ||
| //autogenerate `Query` type | ||
| result = | ||
| // `Query` type for `inappropriateArgumentTypePassedViaEllipsis` query | ||
| TQueryCPP(TPreconditions2PackageQuery(TInappropriateArgumentTypePassedViaEllipsisQuery())) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
cpp/misra/src/rules/RULE-8-2-11/InappropriateArgumentTypePassedViaEllipsis.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| /** | ||
| * @id cpp/misra/inappropriate-argument-type-passed-via-ellipsis | ||
| * @name RULE-8-2-11: An argument passed via ellipsis shall have an appropriate type | ||
| * @description Passing arguments of certain class types via an ellipsis parameter is only | ||
| * conditionally-supported with implementation-defined behaviour. | ||
| * @kind problem | ||
| * @precision very-high | ||
| * @problem.severity error | ||
| * @tags external/misra/id/rule-8-2-11 | ||
| * scope/single-translation-unit | ||
| * correctness | ||
| * external/misra/enforcement/decidable | ||
| * external/misra/obligation/required | ||
| */ | ||
|
|
||
| import cpp | ||
| import codingstandards.cpp.misra | ||
| import codingstandards.cpp.types.TrivialType | ||
|
|
||
| /** | ||
| * Holds if `arg` is an argument passed via ellipsis in `call`. | ||
| */ | ||
| predicate isEllipsisArgument(FunctionCall call, Expr arg, int i) { | ||
| call.getTarget().isVarargs() and | ||
| arg = call.getArgument(i) and | ||
| i >= call.getTarget().getNumberOfParameters() | ||
| } | ||
|
|
||
| /** | ||
| * Holds if `c` has virtual member functions. | ||
| */ | ||
| predicate hasVirtualMemberFunctions(Class c) { c.getAMemberFunction().isVirtual() } | ||
|
|
||
| /** | ||
| * Holds if `c` has non-trivial copy or move operations. | ||
| */ | ||
| predicate hasNonTrivialCopyOrMove(Class c) { | ||
| exists(CopyConstructor cc | cc = c.getAConstructor() | | ||
| not cc instanceof TrivialCopyOrMoveConstructor | ||
| ) | ||
| or | ||
| exists(MoveConstructor mc | mc = c.getAConstructor() | | ||
| not mc instanceof TrivialCopyOrMoveConstructor | ||
| ) | ||
| or | ||
| exists(CopyAssignmentOperator ca | ca = c.getAMemberFunction() | | ||
| not ca instanceof TrivialCopyOrMoveAssignmentOperator | ||
| ) | ||
| or | ||
| exists(MoveAssignmentOperator ma | ma = c.getAMemberFunction() | | ||
| not ma instanceof TrivialCopyOrMoveAssignmentOperator | ||
| ) | ||
| } | ||
|
|
||
| /** | ||
| * Holds if `c` has a non-trivial destructor. | ||
| */ | ||
| predicate hasNonTrivialDestructor(Class c) { not hasTrivialDestructor(c) } | ||
|
|
||
| /** | ||
| * Gets the primary reason why `c` is an inappropriate type to pass via ellipsis, prioritized | ||
| * by the order of conditions in the rule amplification. | ||
| */ | ||
| string getInappropriateReason(Class c) { | ||
| if hasVirtualMemberFunctions(c) | ||
| then result = "has virtual member functions" | ||
| else | ||
| if hasNonTrivialCopyOrMove(c) | ||
| then result = "has non-trivial copy or move operations" | ||
| else ( | ||
| hasNonTrivialDestructor(c) and result = "has a non-trivial destructor" | ||
| ) | ||
| } | ||
|
|
||
| from FunctionCall call, Expr arg, int i, Class argType, string reason | ||
| where | ||
| not isExcluded(arg, Preconditions2Package::inappropriateArgumentTypePassedViaEllipsisQuery()) and | ||
| isEllipsisArgument(call, arg, i) and | ||
| // `arg.getType()` is void for some constructor calls. These seem to have a conversion of class | ||
| // `TemporaryObjectExpr`, which seems to have the correct type. | ||
| argType = arg.getFullyConverted().getUnspecifiedType() and | ||
| reason = getInappropriateReason(argType) and | ||
| // Exclude unevaluated contexts | ||
| not arg.isUnevaluated() and | ||
| not call.isUnevaluated() | ||
| select arg, | ||
| "Argument of type '" + argType.getName() + "' passed via ellipsis to $@ " + reason + ".", | ||
| call.getTarget(), call.getTarget().getName() |
13 changes: 13 additions & 0 deletions
13
cpp/misra/test/rules/RULE-8-2-11/InappropriateArgumentTypePassedViaEllipsis.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| | test.cpp:87:20:87:39 | call to VirtualMemberClass | Argument of type 'VirtualMemberClass' passed via ellipsis to $@ has virtual member functions. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:88:20:88:43 | call to VirtualDestructorClass | Argument of type 'VirtualDestructorClass' passed via ellipsis to $@ has virtual member functions. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:89:20:89:40 | 0 | Argument of type 'NonTrivialCopyClass' passed via ellipsis to $@ has non-trivial copy or move operations. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:90:20:90:40 | 0 | Argument of type 'NonTrivialMoveClass' passed via ellipsis to $@ has non-trivial copy or move operations. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:91:20:91:46 | 0 | Argument of type 'NonTrivialCopyAssignClass' passed via ellipsis to $@ has non-trivial copy or move operations. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:92:20:92:46 | 0 | Argument of type 'NonTrivialMoveAssignClass' passed via ellipsis to $@ has non-trivial copy or move operations. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:93:20:93:46 | 0 | Argument of type 'NonTrivialDestructorClass' passed via ellipsis to $@ has a non-trivial destructor. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:94:20:94:39 | call to DerivedFromVirtual | Argument of type 'DerivedFromVirtual' passed via ellipsis to $@ has virtual member functions. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:95:20:95:40 | call to MultipleIssuesClass | Argument of type 'MultipleIssuesClass' passed via ellipsis to $@ has virtual member functions. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:96:20:96:33 | call to VirtualMemberClass | Argument of type 'VirtualMemberClass' passed via ellipsis to $@ has virtual member functions. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:97:20:97:39 | call to VirtualMemberClass | Argument of type 'VirtualMemberClass' passed via ellipsis to $@ has virtual member functions. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:99:36:99:55 | call to VirtualMemberClass | Argument of type 'VirtualMemberClass' passed via ellipsis to $@ has virtual member functions. | test.cpp:78:6:78:18 | variadic_func | variadic_func | | ||
| | test.cpp:119:25:119:44 | call to VirtualMemberClass | Argument of type 'VirtualMemberClass' passed via ellipsis to $@ has virtual member functions. | test.cpp:115:6:115:26 | variadic_take_objects | variadic_take_objects | |
1 change: 1 addition & 0 deletions
1
cpp/misra/test/rules/RULE-8-2-11/InappropriateArgumentTypePassedViaEllipsis.qlref
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| rules/RULE-8-2-11/InappropriateArgumentTypePassedViaEllipsis.ql |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| // Trivial class - no virtual functions, trivial special members | ||
| struct TrivialClass { | ||
| int m1; | ||
| }; | ||
|
|
||
| // Class with virtual member function | ||
| struct VirtualMemberClass { | ||
| int m1; | ||
| virtual void f1() {} | ||
| }; | ||
|
|
||
| // Class with virtual destructor | ||
| struct VirtualDestructorClass { | ||
| int m1; | ||
| virtual ~VirtualDestructorClass() = default; | ||
| }; | ||
|
|
||
| // Class with user-defined (non-trivial) copy constructor | ||
| struct NonTrivialCopyClass { | ||
| int m1; | ||
| NonTrivialCopyClass() = default; | ||
| NonTrivialCopyClass(const NonTrivialCopyClass &other) {} | ||
| }; | ||
|
|
||
| // Class with user-defined (non-trivial) move constructor | ||
| struct NonTrivialMoveClass { | ||
| int m1; | ||
| NonTrivialMoveClass() = default; | ||
| NonTrivialMoveClass(NonTrivialMoveClass &&other) {} | ||
| }; | ||
|
|
||
| // Class with user-defined (non-trivial) copy assignment operator | ||
| struct NonTrivialCopyAssignClass { | ||
| int m1; | ||
| NonTrivialCopyAssignClass &operator=(const NonTrivialCopyAssignClass &other) { | ||
| } | ||
| }; | ||
|
|
||
| // Class with user-defined (non-trivial) move assignment operator | ||
| struct NonTrivialMoveAssignClass { | ||
| int m1; | ||
| NonTrivialMoveAssignClass &operator=(NonTrivialMoveAssignClass &&other) {} | ||
| }; | ||
|
|
||
| // Class with user-defined (non-trivial) destructor | ||
| struct NonTrivialDestructorClass { | ||
| ~NonTrivialDestructorClass() {} | ||
| }; | ||
|
|
||
| // Derived class inheriting virtual | ||
| struct DerivedFromVirtual : public VirtualMemberClass { | ||
| void f1() override {} | ||
| }; | ||
|
|
||
| // Class with multiple inappropriate properties | ||
| struct MultipleIssuesClass { | ||
| virtual void f1() {} | ||
| MultipleIssuesClass() = default; | ||
| MultipleIssuesClass(const MultipleIssuesClass &) {} | ||
| ~MultipleIssuesClass() {} | ||
| }; | ||
|
|
||
| // Class with defaulted special members (trivial) | ||
| struct DefaultedClass { | ||
| int m1; | ||
| DefaultedClass() = default; | ||
| DefaultedClass(const DefaultedClass &) = default; | ||
| DefaultedClass(DefaultedClass &&) = default; | ||
| DefaultedClass &operator=(const DefaultedClass &) = default; | ||
| DefaultedClass &operator=(DefaultedClass &&) = default; | ||
| ~DefaultedClass() = default; | ||
| }; | ||
|
|
||
| // A typedef for an inappropriate type | ||
| using VirtualAlias = VirtualMemberClass; | ||
|
|
||
| // User-defined variadic function | ||
| void variadic_func(int p1, ...) {} | ||
|
|
||
| void f() { | ||
| variadic_func(0, 42); // COMPLIANT | ||
| variadic_func(0, 3.14); // COMPLIANT | ||
| variadic_func(0, (void *)nullptr); // COMPLIANT | ||
|
|
||
| variadic_func(0, TrivialClass()); // COMPLIANT | ||
| variadic_func(0, DefaultedClass()); // COMPLIANT | ||
| variadic_func(0, VirtualMemberClass()); // NON_COMPLIANT | ||
| variadic_func(0, VirtualDestructorClass()); // NON_COMPLIANT | ||
| variadic_func(0, NonTrivialCopyClass()); // NON_COMPLIANT | ||
| variadic_func(0, NonTrivialMoveClass()); // NON_COMPLIANT | ||
| variadic_func(0, NonTrivialCopyAssignClass()); // NON_COMPLIANT | ||
| variadic_func(0, NonTrivialMoveAssignClass()); // NON_COMPLIANT | ||
| variadic_func(0, NonTrivialDestructorClass()); // NON_COMPLIANT | ||
| variadic_func(0, DerivedFromVirtual()); // NON_COMPLIANT | ||
| variadic_func(0, MultipleIssuesClass()); // NON_COMPLIANT | ||
| variadic_func(0, VirtualAlias()); // NON_COMPLIANT | ||
| variadic_func(0, VirtualMemberClass()); // NON_COMPLIANT | ||
|
|
||
| variadic_func(0, TrivialClass(), VirtualMemberClass()); // NON_COMPLIANT | ||
| } | ||
|
|
||
| void test_unevaluated_context() { | ||
| sizeof(variadic_func(0, VirtualMemberClass())); // COMPLIANT | ||
|
MichaelRFairhurst marked this conversation as resolved.
|
||
| } | ||
|
|
||
| // Parameter pack is not ellipsis | ||
| template <typename... Args> void parameter_pack_func(Args... p1) {} | ||
|
|
||
| void test_parameter_pack() { | ||
| VirtualMemberClass l1; | ||
| NonTrivialCopyClass l2; | ||
| parameter_pack_func(l1, l2); // COMPLIANT | ||
| } | ||
|
|
||
| void variadic_take_objects(VirtualMemberClass v, ...); | ||
| void test_named_parameter_of_variadic_function() { | ||
| variadic_take_objects(VirtualMemberClass()); // COMPLIANT | ||
| variadic_take_objects(VirtualMemberClass(), | ||
| VirtualMemberClass()); // NON_COMPLIANT | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "MISRA-C++-2023": { | ||
| "RULE-8-2-11": { | ||
| "properties": { | ||
| "enforcement": "decidable", | ||
| "obligation": "required" | ||
| }, | ||
| "queries": [ | ||
| { | ||
| "description": "Passing arguments of certain class types via an ellipsis parameter is only conditionally-supported with implementation-defined behaviour.", | ||
| "kind": "problem", | ||
| "name": "An argument passed via ellipsis shall have an appropriate type", | ||
| "precision": "very-high", | ||
| "severity": "error", | ||
| "short_name": "InappropriateArgumentTypePassedViaEllipsis", | ||
| "tags": [ | ||
| "scope/single-translation-unit", | ||
| "correctness" | ||
| ] | ||
| } | ||
| ], | ||
| "title": "An argument passed via ellipsis shall have an appropriate type" | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.