Skip to content

Commit

Permalink
Apply some review comment
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomasz Kamiński committed Jan 24, 2024
1 parent 7be9a36 commit 2679968
Showing 1 changed file with 49 additions and 48 deletions.
97 changes: 49 additions & 48 deletions rules/S6871/cfamily/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,25 @@ and _value-initialized_ in case of records of struct.
[source,c]
----
int a1[5] = {1, 2, 3}; // Noncompliant, last two elements are initialized with 0
int a2[4] = {1, 2, 3, 4, 5}; // Complaint
int* a3[3] = {a1, a1 + 1}; // Noncomplaint, last pointer is null
int* a4[3] = {a1, a1 + 1, nullptr}; // Complaint
int a2[4] = {1, 2, 3, 4, 5}; // Compliant
int* a3[3] = {a1, a1 + 1}; // Noncompliant, last pointer is null
int* a4[3] = {a1, a1 + 1, nullptr}; // Compliant
----

Similarly, when an aggregate class or struct is initialized,
an initial value may be provided for each field.
All reaming fields are initialized in the same manner as
elements of the array:

[source,c]
[source,cpp]
----
struct Pod {
int x;
int y;
};
Pod p1{1}; // Noncomplaint, x is set to 0
Pod p2{1, 0}; // Complaint
Pod p1{1}; // Noncompliant, `y` do not have initial value
Pod p2{1, 0}; // Compliant
----

These rule also applies when arrays and aggregate structs,
Expand All @@ -49,17 +49,17 @@ struct ArrayMember {
};
int c1[2][2] = {{1}, {2}}; // Noncompliant, second element of each nested array does not have an initial value provided
Pod c2[3] = {{1, 2}, {2}}; // Noncomplaint, field `y` of `c[1]` and whole `c[2]` object does not have initial value provided
PodPair c3 = {{1}}; // Noncomplaint, field `y` of `c3.first` and whole `c[2]` object do not have initial value provided,
ArrayMember c4 = {1, 2, 3}; // Noncomplaint, last two elements of array `c4.vals` do not have initial value provided
Pod c2[3] = {{1, 2}, {2}}; // Noncompliant, field `y` of `c2[1]` and whole `c2[2]` object does not have initial value provided
PodPair c3 = {{1}}; // Noncompliant, field `y` of `c3.first` and whole `c3.second` object do not have initial value provided,
ArrayMember c4 = {1, 2, 3}; // Noncompliant, last two elements of array `c4.vals` do not have initial value provided
----

This rule raises issues if such non-zero initialization of aggregate (array or class/struct),
does not provide values for all elements or fields.

=== What is the potential impact?

When the initializer omits the initializer for some of the elements of the array or the field of the aggregate,
When the initializer omits the value for some of the elements of the array or the field of the aggregate,
the intent of the code is unclear.
It is impossible to determine if the initial value was skipped on purpose, or is the result of the later modification of the code,
that changed the size of the array or added a new field to the aggregate class.
Expand All @@ -79,19 +79,19 @@ The issue is not raised in such a situation.

[source,c]
----
int a1[10] = {0}; // Complaint
Pod p1 = {0}; // Complaint
PodPair c1 = {0}; // Complaint
int a1[10] = {0}; // Compliant
Pod p1 = {0}; // Compliant
PodPair c1 = {0}; // Compliant
----

This exception also applies when the nested aggregate is zero-initialized:

[source,cpp]
----
int c1[2][2]{{1, 2}, {}}; // Complaint
Pod c2[3] = {{1, 2}, {}, {}}; // Complaint
PodPair c3 = {{}, {1, 0}}; // Complaint
ArrayMember c4{1, {}}; // Complaint
int c1[2][2]{{1, 2}, {}}; // Compliant
Pod c2[3] = {{1, 2}, {}, {}}; // Compliant
PodPair c3 = {{}, {1, 0}}; // Compliant
ArrayMember c4{1, {}}; // Compliant
----

=== What if designated initializers are used?
Expand All @@ -104,9 +104,9 @@ all elements of fields is not provided.
[source,c]
----
int a1[3] = { [1] = 1, [2] = 2 }; // Noncompliant, first element do not have initial value provided
int a2[3] = { [0] = 0, [1] = 1, [2] = 2 }; // Complaint
int a2[3] = { [0] = 0, [1] = 1, [2] = 2 }; // Compliant
Pod p1 = {.y = 10}; // Noncompliant, `p.x` do not have initial value provided
Pod p2 = {.x = 0, .y = 10}; // Complaint
Pod p2 = {.x = 0, .y = 10}; // Compliant
----

{cpp} have adopted limited version of this feature in {cpp}20 standard,
Expand All @@ -129,10 +129,10 @@ struct Aggr {
int c = 0;
};
Aggr a0{}; // Complaint, zero-initialization
Aggr a0{}; // Compliant, zero-initialization
Aggr a1{10}; // Noncompliant, no initial value for field `b`, which does not have a default value
Aggr a2{10, 20}; // Complaint, field `c` has a default value specified in `Aggr` definition
Aggr a3{10, 20, 30}; // Complaint, all fields have initial values
Aggr a2{10, 20}; // Compliant, field `c` has a default value specified in `Aggr` definition
Aggr a3{10, 20, 30}; // Compliant, all fields have initial values
----

With the use of a designated initializer, such default value is meaningful for non-trailing fields:
Expand All @@ -145,20 +145,21 @@ struct Mid {
};
Mid m1{.a = 10, .b = 10}; // Noncompliant, no initial for field `c` that does not have a default value
Mid m1{.a = 10, .c = 2}; // Complaint, field `b` has a default value specified in `Mid` definition
Mid m1{.a = 10, .c = 2}; // Compliant, field `b` has a default value specified in `Mid` definition
----

=== Why is the issue raised when I use parenthesis?

{cpp}20 allows aggregate types to be initialized using the parenthesis (`()`) in addition to the braces (`{}`).
{cpp}20 allows aggregate types to be initialized using the parenthesis (`()`) in addition to the braces (`{}`),
which simplies writting generic code that creates an object (see rule S6872 for more details).
This syntax still allows skipping initial values of a field or an element of aggregate, and the rule also raises issues in such a situation:

[source,c]
----
int a1[5](1, 2, 3); // Noncompliant, last two elements are initialized with 0
int a2[4](1, 2, 3, 4, 5); // Complaint
Pod p1(1); // Noncomplaint, x does not have inital value
Pod p2(1, 0); // Complaint
int a1[5](1, 2, 3); // Noncompliant, last two elements do not have initial value
int a2[4](1, 2, 3, 4, 5); // Compliant
Pod p1(1); // Noncompliant, `y` does not have inital value
Pod p2(1, 0); // Compliant
----

== How to fix it
Expand Down Expand Up @@ -193,11 +194,11 @@ struct ArrayMember {
int a1[5] = {1, 2, 3}; // Noncompliant
Pod p1{1}; // Noncomplaint
int c1[2][2] = {{1}, {2}}; // Noncomplaint
Pod c2[3] = {{1, 2}, {2}}; // Noncomplaint
PodPair c3 = {{1}}; // Noncomplaint
ArrayMember c4 = {1, 2, 3}; // Noncomplaint
Pod p1{1}; // Noncompliant
int c1[2][2] = {{1}, {2}}; // Noncompliant
Pod c2[3] = {{1, 2}, {2}}; // Noncompliant
PodPair c3 = {{1}}; // Noncompliant
ArrayMember c4 = {1, 2, 3}; // Noncompliant
----

==== Compliant solution
Expand All @@ -221,17 +222,17 @@ struct ArrayMember {
int a1[5] = {1, 2, 3, 0, 0}; // Compliant
Pod p1{1, 0}; // Complaint
int c1[2][2] = {{1, 0}, {2, 0}}; // Complaint
Pod c2[3] = {{1, 2}, {2, 0}, {0, 0}}; // Complaint
PodPair c3 = {{1, 0}, {0, 0}}; // Complaint
ArrayMember c4 = {1, 2, 3, 0, 0, 0}; // Complaint
Pod p1{1, 0}; // Compliant
int c1[2][2] = {{1, 0}, {2, 0}}; // Compliant
Pod c2[3] = {{1, 2}, {2, 0}, {0, 0}}; // Compliant
PodPair c3 = {{1, 0}, {0, 0}}; // Compliant
ArrayMember c4 = {1, 2, 3, 0, 0, 0}; // Compliant
----

Or use zero-initialization syntax for `c2` and `c3`:
-----
Pod c2[3] = {{1, 2}, {2, 0}, {}}; // Complaint
PodPair c3{{1, 0}, {}}; // Complaint
Pod c2[3] = {{1, 2}, {2, 0}, {}}; // Compliant
PodPair c3{{1, 0}, {}}; // Compliant
----

=== Code examples
Expand All @@ -248,8 +249,8 @@ struct ArrayMember {
};
int a1[5] = {0, 0, 0}; // Noncompliant
int c1[2][3] = {{0, 0}, {0, 0}}; // Noncomplaint
ArrayMember c2 = {11}; // Noncomplaint
int c1[2][3] = {{0, 0}, {0, 0}}; // Noncompliant
ArrayMember c2 = {11}; // Noncompliant
----

==== Compliant solution
Expand All @@ -262,16 +263,16 @@ struct ArrayMember {
};
int a1[5] = {0}; // Compliant
int c1[2][3] = {0}; // Complaint
ArrayMember c2 = {11, {0}}; // Complaint
int c1[2][3] = {0}; // Compliant
ArrayMember c2 = {11, {0}}; // Compliant
----

Or in case of {cpp}:
[source,cpp]
-----
int a1[5]{}; // Compliant
int c1[2][3] = {{}, {}}; // Complaint
ArrayMember c2 = {11, {}}; // Complaint
int c1[2][3] = {{}, {}}; // Compliant
ArrayMember c2 = {11, {}}; // Compliant
----

=== Code examples
Expand All @@ -293,7 +294,7 @@ struct ArrayMember {
};
Pod p1{1}; // Noncompliant
ArrayMember m1{11}; // Noncomplaint
ArrayMember m1{11}; // Noncompliant
----

==== Compliant solution
Expand All @@ -311,7 +312,7 @@ struct ArrayMember {
};
Pod p1{1}; // Compliant
ArrayMember m1{11}; // Complaint
ArrayMember m1{11}; // Compliant
----


Expand Down

0 comments on commit 2679968

Please sign in to comment.