emmettneyman updated this revision to Diff 210649.
emmettneyman added a comment.

Created diagnostic group, added behavior and documentation for private fields, 
added documentation regarding GCC attribute


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64380/new/

https://reviews.llvm.org/D64380

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test
  clang/test/SemaCXX/attr-requires-designator.cpp
  clang/test/SemaCXX/attr-requires-init.cpp

Index: clang/test/SemaCXX/attr-requires-init.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/attr-requires-init.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+[[clang::requires_init]] int x;            // expected-warning{{'requires_init' attribute only applies to non-static data members}}
+[[clang::requires_init]] void fun(int x) { // expected-warning{{'requires_init' attribute only applies to non-static data members}}
+  return;
+}
+struct [[clang::requires_init]] Foo { // expected-warning{{'requires_init' attribute only applies to non-static data members}}
+  int x;
+};
+
+// Struct with one required field
+struct Bar {
+  [[clang::requires_init]] int y; // expected-note 0+ {{enforced by 'requires_init' attribute here}}
+};
+
+// The following are invalid ways of initializing instances of this struct.
+Bar b1;    // expected-warning{{initializer for variable b1 must explicitly initialize field y}}
+Bar b2{};  // expected-warning{{initializer for variable b2 must explicitly initialize field y}}
+Bar b3{1}; // expected-warning{{initializer for variable b3 must explicitly initialize field y}}
+
+// The following are valid ways of initializing instances of this struct.
+Bar b6{.y = 1};
+
+// Struct with multiple required fields
+struct Baz {
+  [[clang::requires_init]] int x; // expected-note 0+ {{enforced by 'requires_init' attribute here}}
+  int y;
+  [[clang::requires_init]] int z; // expected-note 0+ {{enforced by 'requires_init' attribute here}}
+};
+
+// The following are invalid ways of initializing instances of this struct.
+Baz z1;                 // expected-warning{{initializer for variable z1 must explicitly initialize field x}} expected-warning{{initializer for variable z1 must explicitly initialize field z}}
+Baz z2{};               // expected-warning{{initializer for variable z2 must explicitly initialize field x}} expected-warning{{initializer for variable z2 must explicitly initialize field z}}
+Baz z3{1, 2};           // expected-warning{{initializer for variable z3 must explicitly initialize field x}} expected-warning{{initializer for variable z3 must explicitly initialize field z}}
+Baz z4{1, 2, 3};        // expected-warning{{initializer for variable z4 must explicitly initialize field x}} expected-warning{{initializer for variable z4 must explicitly initialize field z}}
+Baz z5{.x = 1, 2};      // expected-warning{{initializer for variable z5 must explicitly initialize field z}}
+Baz z6{.x = 1, .y = 2}; // expected-warning{{initializer for variable z6 must explicitly initialize field z}}
+
+// The following are valid ways of initializing instances of this struct.
+Baz z7{.x = 1, .y = 2, .z = 3};
+Baz z8{.x = 1, .z = 3};
+Baz z9{.x = 1, 2, .z = 3};
+
+// The requires_init attribute can also be applied to public fields of classes.
+class Cla {
+public:
+  [[clang::requires_init]] int x; // expected-note 0+ {{enforced by 'requires_init' attribute here}}
+  int y;
+};
+
+// The following are invalid ways of initializing instances of this class.
+Cla c1;            // expected-warning{{initializer for variable c1 must explicitly initialize field x}}
+Cla c2{};          // expected-warning{{initializer for variable c2 must explicitly initialize field x}}
+Cla c3{1};         // expected-warning{{initializer for variable c3 must explicitly initialize field x}}
+Cla c4{1, 2};      // expected-warning{{initializer for variable c4 must explicitly initialize field x}}
+Cla c5{1, .y = 2}; // expected-warning{{initializer for variable c5 must explicitly initialize field x}}
+
+// The following are valid ways of initializing instances of this class.
+Cla c6{.x = 1};
+Cla c7{.x = 1, .y = 2};
+Cla c8{.x = 1, 2};
+
+// This attribute cannot be applied to fields of a union.
+union Uni {
+  [[clang::requires_init]] int x; // expected-warning{{'requires_init' attribute ignored}}
+  int y;
+};
+
+// If any of the fields in the record are non-public all requires_init
+// attributes in the record are ignored.
+struct PriMems {
+  [[clang::requires_init]] int x; // expected-warning{{'requires_init' attribute ignored}}
+private:
+  int y;
+};
+PriMems pm1;
+PriMems pm2();
+
+class PriClass {
+  int x;
+public:
+  [[clang::requires_init]] int y; // expected-warning{{'requires_init' attribute ignored}}
+  int z;
+};
+PriClass pc1;
+PriClass pc2();
Index: clang/test/SemaCXX/attr-requires-designator.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/attr-requires-designator.cpp
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// The requires_designator attribute only applies to types. It will
+// generate a warning when attached to variables, functions, arrays, etc.
+[[clang::requires_designator]] int x;            // expected-warning{{'requires_designator' attribute only applies to structs, unions, and classes}}
+[[clang::requires_designator]] void fun(int x) { // expected-warning{{'requires_designator' attribute only applies to structs, unions, and classes}}
+  return;
+}
+[[clang::requires_designator]] int arr[10]; // expected-warning{{'requires_designator' attribute only applies to structs, unions, and classes}}
+
+// Struct with one field with requires_designator attribute
+struct [[clang::requires_designator]] Foo { // expected-note 0+ {{required by 'requires_designator' attribute here}}
+  int a;
+};
+
+// The following are invalid ways of initializing instances of this struct.
+Foo f1;       // expected-warning{{variable declaration does not use designated initializer syntax}}
+Foo f2{1};    // expected-warning{{variable declaration does not use designated initializer syntax}}
+Foo f3 = {1}; // expected-warning{{variable declaration does not use designated initializer syntax}}
+// The following are valid ways of initializing instances of this struct.
+Foo f4{};
+Foo f5 = {};
+Foo f6{.a = 1};
+Foo f7 = {.a = 1};
+
+// Struct with multiple fields wth requires_designator attribute
+struct [[clang::requires_designator]] Bar { // expected-note 0+ {{required by 'requires_designator' attribute here}}
+  int b;
+  int c;
+};
+
+// The following are invalid ways of initializing instances of this struct.
+Bar b1;               // expected-warning{{variable declaration does not use designated initializer syntax}}
+Bar b2{1, 2};         // expected-warning{{variable declaration does not use designated initializer syntax}}
+Bar b3 = {1, 2};      // expected-warning{{variable declaration does not use designated initializer syntax}}
+Bar b4{.b = 1, 2};    // expected-warning{{variable declaration does not use designated initializer syntax}}
+Bar b5 = {.b = 1, 2}; // expected-warning{{variable declaration does not use designated initializer syntax}}
+// The following are valid ways of initializing instances of this struct.
+Bar b6{};
+Bar b7 = {};
+Bar b8{.b = 1};
+Bar b9 = {.b = 1};
+Bar b10{.b = 1, .c = 2};
+Bar b11 = {.b = 1, .c = 2};
+Bar b12 = {.c = 2, .b = 1};
+
+// Struct without requires_designator attribute
+struct Baz {
+  int d;
+  int e;
+};
+
+// The following are all valid ways of initializing instances of this struct.
+Baz z1;
+Baz z2{};
+Baz z3 = {};
+Baz z4{1, 2};
+Baz z5 = {1, 2};
+Baz z6{.d = 1, .e = 2};
+Baz z7 = {.d = 1, .e = 2};
+Baz z8{1};
+Baz z9 = {1};
+Baz z10{.d = 1, 2};
+Baz z11 = {.d = 1, 2};
+
+// The requires_designator attribute can also be attached to unions.
+union [[clang::requires_designator]] Uni { // expected-note 0+ {{required by 'requires_designator' attribute here}}
+  int x;
+  int y;
+};
+
+// The following are invalid ways of initializing instances of this union.
+Uni u1;       // expected-warning{{variable declaration does not use designated initializer syntax}}
+Uni u2{1};    // expected-warning{{variable declaration does not use designated initializer syntax}}
+Uni u3 = {1}; // expected-warning{{variable declaration does not use designated initializer syntax}}
+// The following are valid ways of initializing instances of this union.
+Uni u4{};
+Uni u5 = {};
+Uni u6{.x = 1};
+Uni u7 = {.x = 1};
+
+// The requires_designator attribute can also be attached to classes.
+class [[clang::requires_designator]] Cla { // expected-note 0+ {{required by 'requires_designator' attribute here}}
+public:
+  int x;
+  int y;
+};
+
+// The following are invalid ways of initializing instances of this class.
+Cla c1;               // expected-warning{{variable declaration does not use designated initializer syntax}}
+Cla c2{1, 2};         // expected-warning{{variable declaration does not use designated initializer syntax}}
+Cla c3 = {1, 2};      // expected-warning{{variable declaration does not use designated initializer syntax}}
+Cla c4{.x = 1, 2};    // expected-warning{{variable declaration does not use designated initializer syntax}}
+Cla c5 = {.x = 1, 2}; // expected-warning{{variable declaration does not use designated initializer syntax}}
+// The following are valid ways of initializing instances of this class.
+Cla c6{};
+Cla c7 = {};
+Cla c8{.x = 1};
+Cla c9 = {.x = 1};
+Cla c10{.x = 1, .y = 2};
+Cla c11 = {.x = 1, .y = 2};
+Cla c12 = {.y = 2, .x = 1};
+
+// The requires_designator attribute is ignored when attached to a record with
+// non-public members.
+struct [[clang::requires_designator]] Pri { // expected-warning{{'requires_designator' attribute ignored}}
+  int x;
+private:
+  int y;
+};
+Pri pri1;
+Pri pri2();
+
+struct [[clang::requires_designator]] Pro { // expected-warning{{'requires_designator' attribute ignored}}
+  int x;
+protected:
+  int y;
+};
+Pro pro1;
+Pro pro2();
+
+class [[clang::requires_designator]] PriClass { // expected-warning{{'requires_designator' attribute ignored}}
+  int x;
+public:
+  int y;
+};
+Pro pc1;
+Pro pc2();
+
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -122,6 +122,8 @@
 // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
 // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)
 // CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: RequiresDesignator (SubjectMatchRule_record)
+// CHECK-NEXT: RequiresInit (SubjectMatchRule_field)
 // CHECK-NEXT: Restrict (SubjectMatchRule_function)
 // CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -5309,6 +5309,19 @@
                                          AL.getAttributeSpellingListIndex()));
 }
 
+static void handleRequiresInitAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  if (auto *FD = dyn_cast<FieldDecl>(D)) {
+    auto const *RD = FD->getParent();
+    if (RD->isUnion())
+      S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName();
+    else {
+      FD->addAttr(::new (S.Context) RequiresInitAttr(
+          AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+    }
+  } else
+    S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName();
+}
+
 static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) {
   StringRef MetaDataName;
   if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName))
@@ -6959,6 +6972,12 @@
   case ParsedAttr::AT_RequireConstantInit:
     handleSimpleAttribute<RequireConstantInitAttr>(S, D, AL);
     break;
+  case ParsedAttr::AT_RequiresDesignator:
+    handleSimpleAttribute<RequiresDesignatorAttr>(S, D, AL);
+    break;
+  case ParsedAttr::AT_RequiresInit:
+    handleRequiresInitAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_InitPriority:
     handleInitPriorityAttr(S, D, AL);
     break;
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -11211,6 +11211,79 @@
     Init = Result.get();
   }
 
+  if (const auto *TD = VDecl->getType().getTypePtr()->getAsTagDecl()) {
+    // If the type of the declaration is a struct/class and that type has the
+    // require_designated_init attribute, check that the initializer has
+    // the proper designated initializer syntax.
+    if (const auto *RAttr = TD->getAttr<RequiresDesignatorAttr>()) {
+      if (const auto *ILE = dyn_cast<InitListExpr>(Init)) {
+        for (const auto *I : ILE->inits()) {
+          if (isa<DesignatedInitExpr>(I))
+            continue;
+          SourceRange SR(VDecl->getSourceRange().getBegin(),
+                         Init->getSourceRange().getEnd());
+          Diag(I->getExprLoc(), diag::warn_requires_designator_failed)
+              << SR;
+          Diag(RAttr->getLocation(),
+               diag::note_declared_requires_designator_here)
+              << RAttr->getRange();
+          VDecl->setInvalidDecl();
+          return;
+        }
+      }
+    }
+
+    // If the type of the declaration is a struct/class, we must check whether
+    // any of the fields have the required attribute. If any of them do, we must
+    // confirm that each of those fields are initialized with designated
+    // initializer syntax.
+    if (const auto *RD = dyn_cast<RecordDecl>(TD)) {
+      // Iterate through all the fields of the record and add all of the
+      // required fields to a set. The field will be removed later if it is
+      // properly initialized.
+      std::set<IdentifierInfo *> RequiredFields;
+      for (const auto *FD : RD->fields()) {
+        if (FD->hasAttr<RequiresInitAttr>()) {
+          RequiredFields.insert(FD->getIdentifier());
+        }
+      }
+      // Iterate through all the initializers and remove a field from the set if
+      // it is initialized correctly using designated initializer syntax.
+      if (RequiredFields.size() > 0) {
+        if (const auto *ILE = dyn_cast<InitListExpr>(Init)) {
+          for (const auto *I : ILE->inits()) {
+            if (const auto *DIE = dyn_cast<DesignatedInitExpr>(I)) {
+              const auto *D = DIE->getDesignator(0);
+              if (D->isFieldDesignator()) {
+                IdentifierInfo *Name = D->getFieldName();
+                if (RequiredFields.count(Name) != 0)
+                  RequiredFields.erase(Name);
+              }
+            }
+          }
+        }
+        // Iterate through all the remaining fields and emit a diagnostic for
+        // each field.
+        for (const auto FD : RD->fields()) {
+          if (RequiredFields.count(FD->getIdentifier()) != 0) {
+            SourceRange SR(VDecl->getSourceRange().getBegin(),
+                           Init->getSourceRange().getEnd());
+            Diag(Init->getExprLoc(), diag::warn_requires_init_failed)
+                << SR << VDecl->getName() << FD->getName();
+            const auto *A = FD->getAttr<RequiresInitAttr>();
+            Diag(A->getLocation(), diag::note_declared_requires_init_here)
+                << A->getRange();
+            VDecl->setInvalidDecl();
+            RequiredFields.erase(FD->getIdentifier());
+          }
+        }
+        // Return here so all attribute violation errors get emitted.
+        if (VDecl->isInvalidDecl())
+          return;
+      }
+    }
+  }
+
   // Perform the initialization.
   ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
   if (!VDecl->isInvalidDecl()) {
@@ -11552,6 +11625,37 @@
   if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
     QualType Type = Var->getType();
 
+    if (const auto *TD = Type.getTypePtr()->getAsTagDecl()) {
+      // If the type of the declaration is a struct/class and that type has the
+      // require_designated_init attribute, an initializer is mandatory.
+      if (const auto *A = TD->getAttr<RequiresDesignatorAttr>()) {
+        Diag(Var->getLocation(), diag::warn_requires_designator_failed)
+            << Var->getSourceRange();
+        Diag(A->getLocation(),
+             diag::note_declared_requires_designator_here)
+            << A->getRange();
+        Var->setInvalidDecl();
+        return;
+      }
+      // If the type of the declaration is a struct/class, we must check whether
+      // any of the fields have the required attribute. For each that does, emit
+      // an error since it is not initialized with designated initializer
+      // syntax.
+      if (const auto *RD = dyn_cast<RecordDecl>(TD)) {
+        for (const auto *FD : RD->fields()) {
+          if (const auto *A = FD->getAttr<RequiresInitAttr>()) {
+            Diag(Var->getLocation(), diag::warn_requires_init_failed)
+                << Var->getSourceRange() << Var->getName() << FD->getName();
+            Diag(A->getLocation(), diag::note_declared_requires_init_here)
+                << A->getRange();
+            Var->setInvalidDecl();
+          }
+        }
+        if (Var->isInvalidDecl())
+          return;
+      }
+    }
+
     // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory.
     if (isa<DecompositionDecl>(RealDecl)) {
       Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var;
@@ -15207,6 +15311,36 @@
   TagDecl *Tag = cast<TagDecl>(TagD);
   Tag->setBraceRange(BraceRange);
 
+  // If this TagDecl has any non-public fields, all requires_designator and
+  // requires_init attributes should be ignored.
+  bool AllMembersPublic = true;
+  if (const auto *RD = dyn_cast<RecordDecl>(Tag)) {
+    for (auto const *FD : RD->fields()) {
+      if (FD->getAccess() != AS_public)
+        AllMembersPublic = false;
+    }
+    if (!AllMembersPublic) {
+      if (const auto *RDAttr = Tag->getAttr<RequiresDesignatorAttr>()) {
+        auto Attrs = Tag->getAttrs();
+        Tag->dropAttrs();
+        Attrs.erase(std::remove(Attrs.begin(), Attrs.end(), RDAttr),
+                     Attrs.end());
+        Tag->setAttrs(Attrs);
+        Diag(RDAttr->getLocation(), diag::warn_attribute_ignored) << RDAttr;
+      }
+      for (auto *FD : RD->fields()) {
+        if (const auto *RIAttr = FD->getAttr<RequiresInitAttr>()) {
+          auto Attrs = FD->getAttrs();
+          FD->dropAttrs();
+          Attrs.erase(std::remove(Attrs.begin(), Attrs.end(), RIAttr),
+                       Attrs.end());
+          FD->setAttrs(Attrs);
+          Diag(RIAttr->getLocation(), diag::warn_attribute_ignored) << RIAttr;
+        }
+      }
+    }
+  }
+
   // Make sure we "complete" the definition even it is invalid.
   if (Tag->isBeingDefined()) {
     assert(Tag->isInvalidDecl() && "We should already have completed it");
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3530,6 +3530,17 @@
   "'objc_designated_initializer' attribute only applies to init methods "
   "of interface or class extension declarations">;
 
+def warn_requires_designator_failed : Warning<
+  "variable declaration does not use designated initializer syntax">,
+  InGroup<DesignatedInit>;
+def note_declared_requires_designator_here : Note<
+  "required by 'requires_designator' attribute here">;
+def warn_requires_init_failed : Warning<
+  "initializer for variable %0 must explicitly initialize field %1">,
+  InGroup<DesignatedInit>;
+def note_declared_requires_init_here : Note<
+  "enforced by 'requires_init' attribute here">;
+
 // objc_bridge attribute diagnostics.
 def err_objc_attr_not_id : Error<
   "parameter of %0 attribute must be a single name of an Objective-C %select{class|protocol}1">;
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -1065,3 +1065,6 @@
 def CTADMaybeUnsupported : DiagGroup<"ctad-maybe-unsupported">;
 
 def FortifySource : DiagGroup<"fortify-source">;
+
+// Warnings for requires_designator and requires_init attributes
+def DesignatedInit : DiagGroup<"designated-init">;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -1445,6 +1445,77 @@
   }];
 }
 
+def RequiresDesignatorDocs : Documentation {
+  let Category = DocCatType;
+  let Content = [{
+This attribute can be applied to a struct definition to require that any time a
+variable of that structure's type is declared, the declaration uses designated
+initializer syntax ([dcl.init.aggr]p3.1).
+For a struct ``Foo`` with one integer field ``x``, the following declarations
+are valid and invalid when this attribute is applied to the struct's definition.
+
+.. code-block:: c++
+
+  Foo foo {.x = 1}; // valid
+  Foo foo {}; // valid
+  Foo foo {1}; // invalid
+  Foo foo; // invalid
+
+For a struct ``Foo`` with three integer fields ``x``, ``y``, and ``z``, the
+following declarations are valid and invalid when this attribute is applied to
+the struct's definition.
+
+.. code-block:: c++
+
+  Foo foo {.x = 1, .y = 2, .z = 3}; // valid
+  Foo foo {.z = 3, .x = 1, .y = 2}; // valid
+  Foo foo {.x = 1, .z = 3}; // valid
+  Foo foo {}; // valid
+  Foo foo {1, 2, 3}; // invalid
+  Foo foo; // invalid
+
+This attribute can similarly be applied to union types, requiring that all
+declarations of that union type use designated initializer syntax to initialize
+the field. If the struct or class to which this attribute is applied has any
+non-public fields, this attribute will be ignored.
+
+This attribute is similar to GCC's ``designated_init`` attribute in that it
+requires designated initializers be used rather than positional initializers.
+This attribute additionally has a stronger restriction that declarations must be
+brace-initialized (which is why ``Foo foo;`` is considered invalid above. The
+final way this attribute differs from GCC's ``designated_init`` attribute is
+that it can be applied to union and class types, as well as struct types.
+  }];
+}
+
+def RequiresInitDocs : Documentation {
+  let Category = DocCatType;
+  let Content = [{
+This attribute can be applied to a field definition within a struct or a class
+to require that any time a variable of the struct's type is declared, that field
+must be initialized using designated initializer syntax ([dcl.init.aggr]p3.1).
+A field marked with this attribute may not be omitted or default-constructed.
+For a struct ``Foo`` with a ``designated_init_required`` integer field ``x``,
+the following declarations are valid and invalid.
+
+.. code-block:: c++
+
+  struct Foo {
+    [[clang::requires_init]] int x;
+  };
+
+  Foo foo; // invalid
+  Foo foo {}; // invalid
+  Foo foo {1}; // invalid
+  Foo foo {.x = 1}; // valid
+
+This attribute cannot be applied to fields in a union. If it is, a warning will
+be emitted and the attribute will be ignored. This attribute is also ignored
+if any of the fields in the struct/class are non-public, regardless of whether
+the non-public field is marked as ``requires_init``.
+  }];
+}
+
 def WarnMaybeUnusedDocs : Documentation {
   let Category = DocCatVariable;
   let Heading = "maybe_unused, unused";
@@ -4194,4 +4265,4 @@
 not initialized on device side. It has internal linkage and is initialized by
 the initializer on host side.
   }];
-}
\ No newline at end of file
+}
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1944,6 +1944,18 @@
   let LangOpts = [CPlusPlus];
 }
 
+def RequiresDesignator : InheritableAttr {
+  let Spellings = [Clang<"requires_designator">, GCC<"designated_init">];
+  let Subjects = SubjectList<[Record]>;
+  let Documentation = [RequiresDesignatorDocs];
+}
+
+def RequiresInit : InheritableAttr {
+  let Spellings = [Clang<"requires_init">];
+  let Subjects = SubjectList<[Field]>;
+  let Documentation = [RequiresInitDocs];
+}
+
 def WorkGroupSizeHint :  InheritableAttr {
   // Does not have a [[]] spelling because it is an OpenCL-related attribute.
   let Spellings = [GNU<"work_group_size_hint">];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to