[clang] Add Clang attribute to ensure that fields are initialized explicitly (PR #102040)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 21 10:13:43 PST 2024


================
@@ -1472,3 +1472,105 @@ template<typename T> struct Outer {
   };
 };
 Outer<int>::Inner outerinner;
+
+void aggregate() {
+  struct NonAgg {
+    NonAgg() { }
+    [[clang::requires_explicit_initialization]] int na;  // expected-warning {{'requires_explicit_initialization' attribute is ignored in non-aggregate type 'NonAgg'}}
+  };
+  NonAgg nonagg;  // no-warning
+  (void)nonagg;
+
+  struct S {
+    [[clang::requires_explicit_initialization]] int s1; // #FIELD_S1
+    int s2;
+    int s3 = 12;
+    [[clang::requires_explicit_initialization]] int s4 = 100; // #FIELD_S4
+    static void foo(S) { }
+  };
+
+  struct C {
+    [[clang::requires_explicit_initialization]] int c1; // #FIELD_C1
+    C() = default;  // Test pre-C++20 aggregates
+  };
+
+  struct D : S { // #TYPE_D
+    int d1;
+    int d2 [[clang::requires_explicit_initialization]]; // #FIELD_D2
+  };
+
+  struct D2 : D {  // #TYPE_D2
+  };
+
+  struct E {  // #TYPE_E
+    int e1;
+    D e2 [[clang::requires_explicit_initialization]]; // #FIELD_E2
+    struct {
+      [[clang::requires_explicit_initialization]] D e3;
+      D2 e4 [[clang::requires_explicit_initialization]];
+    };
+  };
+
+  S::foo(S{1, 2, 3, 4});
+  S::foo(S{.s1 = 100, .s4 = 100});
+  S::foo(S{.s1 = 100}); // expected-warning {{field 's4' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S4 {{'s4' declared here}}
+
+  S s{.s1 = 100, .s4 = 100};
+  (void)s;
+
+  S t{.s4 = 100}; // expected-warning {{field 's1' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S1 {{'s1' declared here}}
+  (void)t;
+
+  S *ptr1 = new S; // expected-warning {{field in 'S' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S4 {{'s4' declared here}} expected-note@#FIELD_S1 {{'s1' declared here}}
+  delete ptr1;
+
+  S *ptr2 = new S{.s1 = 100, .s4 = 100};
+  delete ptr2;
+
+#if __cplusplus >= 202002L
+  // expected-warning at +2 {{field 'd2' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_D2 {{'d2' declared here}}
+  // expected-warning {{field 's1' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S1 {{'s1' declared here}}
+  D a({}, 0);
+  (void)a;
+#else
+  C a; // expected-warning {{field in 'C' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_C1 {{'c1' declared here}}
+  (void)a;
+#endif
+
+  // expected-warning at +2 {{field 's4' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S4 {{'s4' declared here}}
+  // expected-warning at +1 {{field 's1' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S1 {{'s1' declared here}}
+  D b{.d2 = 1};
+  (void)b;
+
+  // expected-warning at +3 {{field 's4' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S4 {{'s4' declared here}}
+  // expected-warning at +2 {{field 'd2' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_D2 {{'d2' declared here}}
+  // expected-warning at +1 {{field 's1' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S1 {{'s1' declared here}}
+  D c{.d1 = 5};
+
+  // expected-warning at +3 {{field 's4' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S4 {{'s4' declared here}}
+  // expected-warning at +2 {{field 'd2' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_D2 {{'d2' declared here}}
+  // expected-warning at +1 {{field 's1' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S1 {{'s1' declared here}}
+  c = {{}, 0};
+  (void)c;
+
+  // expected-note at +3 {{in implicit default constructor for 'D' first required here}}
+  // expected-warning@#TYPE_D {{field in 'S' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_S1 {{'s1' declared here}} expected-note@#FIELD_S4 {{'s4' declared here}}
+  // expected-warning at +1 {{field in 'D' is not explicitly initialized, but was marked as requiring explicit initialization}} expected-note@#FIELD_D2 {{'d2' declared here}}
+  D d;
+  (void)d;
+
+  // expected-warning at +12 {{field in 'E' is not explicitly initialized, but was marked as requiring explicit initialization}}
+  // expected-note@#FIELD_E2 {{'e2' declared here}}
+  // expected-warning@#TYPE_E {{field in 'D' is not explicitly initialized, but was marked as requiring explicit initialization}}
+  // expected-note at +9 {{in implicit default constructor for 'E' first required here}}
+  // expected-note@#FIELD_D2 {{'d2' declared here}}
+  // expected-warning@#TYPE_E {{field in 'D' is not explicitly initialized, but was marked as requiring explicit initialization}}
+  // expected-note@#FIELD_D2 {{'d2' declared here}}
+  // expected-warning@#TYPE_E {{field in 'D2' is not explicitly initialized, but was marked as requiring explicit initialization}}
+  // expected-note@#TYPE_E {{in implicit default constructor for 'D2' first required here}}
+  // expected-warning@#TYPE_D2 {{field in 'D' is not explicitly initialized, but was marked as requiring explicit initialization}}
+  // expected-note at +2 {{in implicit default constructor for 'E' first required here}}
+  // expected-note@#FIELD_D2 {{'d2' declared here}}
+  E e;
+  (void)e;
+}
----------------
AaronBallman wrote:

Hmm, I can probably live with not handling the third bullet but I think we're going to want those guard rails at some point. We can burn that bridge when we come to it though.

https://github.com/llvm/llvm-project/pull/102040


More information about the cfe-commits mailing list