sgilles created this revision.
sgilles added reviewers: cfe-commits, rsmith, zaks.anna.

Add ZeroInitializer as a language option, attached to all standards of
C. Relax checks for -Wmissing-field-initializers and -Wmissing-braces so
that, for such languages, assigning to a structure with { 0 } produces
no warnings.  Add tests.

This fixes PR21689, which is mentioned by the Austin Group at
http://austingroupbugs.net/view.php?id=918 .  It does not extend this
treatment of { 0 } to C++.

Patch by S. Gilles


https://reviews.llvm.org/D28148

Files:
  include/clang/Basic/LangOptions.def
  include/clang/Frontend/LangStandard.h
  include/clang/Frontend/LangStandards.def
  lib/Frontend/CompilerInvocation.cpp
  lib/Sema/SemaInit.cpp
  test/Sema/zero-initializer.c

Index: test/Sema/zero-initializer.c
===================================================================
--- /dev/null
+++ test/Sema/zero-initializer.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c99 -Wmissing-field-initializers -Wmissing-braces
+
+struct foo {
+        /* */
+        int x;
+        int y;
+};
+
+struct bar {
+        /* */
+        struct foo a;
+        struct foo b;
+};
+
+int main(void)
+{
+        struct foo f = { 0 }; // expected-no-diagnostics
+        struct foo g = { 9 }; // expected-warning {{missing field 'y' initializer}}
+        struct foo h = { 9, 9 }; // expected-no-diagnostics
+        struct bar i = { 0 }; // expected-no-diagnostics
+        struct bar j = { 0, 0 }; // expected-warning {{suggest braces around initialization of suboject}} expected-warning {{missing field 'b' initializer}}
+        struct bar k = { { 9, 9 }, { 9, 9 } }; // expected-no-diagnostics
+        struct bar l = { { 9, 9 }, { 0 } }; // expected-no-diagnostics
+        struct bar m = { { 0 }, { 0 } }; // expected-no-diagnostics
+        struct bar n = { { 0 }, { 9, 9 } }; // expected-no-diagnostics
+        struct bar o = { { 9, 9 }, { 0 } }; // expected-no-diagnostics
+        struct bar p = { { 9 }, { 9, 9 } }; // expected-warning {{missing field 'y' initializer}}
+
+        return f.x + g.x + h.x + i.a.x + j.a.x + k.a.x + l.a.x + m.a.x + n.a.x +
+               o.a.x + p.a.x;
+}
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -880,8 +880,19 @@
       StructuredSubobjectInitList->setRBraceLoc(EndLoc);
     }
 
+    bool MissingBracesOkay = false;
+
+    if (SemaRef.getLangOpts().ZeroInitializer &&
+        StructuredSubobjectInitList->getNumInits() == 1) {
+      if (const IntegerLiteral *lit = dyn_cast<IntegerLiteral>(StructuredSubobjectInitList->getInit(0))) {
+        if (lit->getValue() == 0) {
+          MissingBracesOkay = true;
+        }
+      }
+    }
+
     // Complain about missing braces.
-    if (T->isArrayType() || T->isRecordType()) {
+    if (!MissingBracesOkay && (T->isArrayType() || T->isRecordType())) {
       SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
                    diag::warn_missing_braces)
           << StructuredSubobjectInitList->getSourceRange()
@@ -1828,6 +1839,17 @@
   RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
   RecordDecl::field_iterator FieldEnd = RD->field_end();
   bool CheckForMissingFields = true;
+
+  // Check if this is C's zero initializer { 0 }
+  if (SemaRef.getLangOpts().ZeroInitializer &&
+      IList->getNumInits() == 1) {
+    if (const IntegerLiteral *lit = dyn_cast<IntegerLiteral>(IList->getInit(0))) {
+      if (lit->getValue() == 0) {
+        CheckForMissingFields = false;
+      }
+    }
+  }
+
   while (Index < IList->getNumInits()) {
     Expr *Init = IList->getInit(Index);
 
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1599,6 +1599,7 @@
   Opts.GNUInline = Std.isC89();
   Opts.HexFloats = Std.hasHexFloats();
   Opts.ImplicitInt = Std.hasImplicitInt();
+  Opts.ZeroInitializer = Std.hasZeroInitializer();
 
   // Set OpenCL Version.
   Opts.OpenCL = isOpenCL(LangStd) || IK == IK_OpenCL;
Index: include/clang/Frontend/LangStandards.def
===================================================================
--- include/clang/Frontend/LangStandards.def
+++ include/clang/Frontend/LangStandards.def
@@ -30,66 +30,66 @@
 // C89-ish modes.
 LANGSTANDARD(c89, "c89",
              "ISO C 1990",
-             C89 | ImplicitInt)
+             C89 | ImplicitInt | ZeroInitializer)
 LANGSTANDARD(c90, "c90",
              "ISO C 1990",
-             C89 | ImplicitInt)
+             C89 | ImplicitInt | ZeroInitializer)
 LANGSTANDARD(iso9899_1990, "iso9899:1990",
              "ISO C 1990",
-             C89 | ImplicitInt)
+             C89 | ImplicitInt | ZeroInitializer)
 
 LANGSTANDARD(c94, "iso9899:199409",
              "ISO C 1990 with amendment 1",
-             C89 | Digraphs | ImplicitInt)
+             C89 | Digraphs | ImplicitInt | ZeroInitializer)
 
 LANGSTANDARD(gnu89, "gnu89",
              "ISO C 1990 with GNU extensions",
-             LineComment | C89 | Digraphs | GNUMode | ImplicitInt)
+             LineComment | C89 | Digraphs | GNUMode | ImplicitInt | ZeroInitializer)
 LANGSTANDARD(gnu90, "gnu90",
              "ISO C 1990 with GNU extensions",
-             LineComment | C89 | Digraphs | GNUMode | ImplicitInt)
+             LineComment | C89 | Digraphs | GNUMode | ImplicitInt | ZeroInitializer)
 
 // C99-ish modes
 LANGSTANDARD(c99, "c99",
              "ISO C 1999",
-             LineComment | C99 | Digraphs | HexFloat)
+             LineComment | C99 | Digraphs | HexFloat | ZeroInitializer)
 LANGSTANDARD(c9x, "c9x",
              "ISO C 1999",
-             LineComment | C99 | Digraphs | HexFloat)
+             LineComment | C99 | Digraphs | HexFloat | ZeroInitializer)
 LANGSTANDARD(iso9899_1999,
              "iso9899:1999", "ISO C 1999",
-             LineComment | C99 | Digraphs | HexFloat)
+             LineComment | C99 | Digraphs | HexFloat | ZeroInitializer)
 LANGSTANDARD(iso9899_199x,
              "iso9899:199x", "ISO C 1999",
-             LineComment | C99 | Digraphs | HexFloat)
+             LineComment | C99 | Digraphs | HexFloat | ZeroInitializer)
 
 LANGSTANDARD(gnu99, "gnu99",
              "ISO C 1999 with GNU extensions",
-             LineComment | C99 | Digraphs | GNUMode | HexFloat)
+             LineComment | C99 | Digraphs | GNUMode | HexFloat | ZeroInitializer)
 LANGSTANDARD(gnu9x, "gnu9x",
              "ISO C 1999 with GNU extensions",
-             LineComment | C99 | Digraphs | GNUMode | HexFloat)
+             LineComment | C99 | Digraphs | GNUMode | HexFloat | ZeroInitializer)
 
 // C11 modes
 LANGSTANDARD(c11, "c11",
              "ISO C 2011",
-             LineComment | C99 | C11 | Digraphs | HexFloat)
+             LineComment | C99 | C11 | Digraphs | HexFloat | ZeroInitializer)
 LANGSTANDARD(c1x, "c1x",
              "ISO C 2011",
-             LineComment | C99 | C11 | Digraphs | HexFloat)
+             LineComment | C99 | C11 | Digraphs | HexFloat | ZeroInitializer)
 LANGSTANDARD(iso9899_2011,
              "iso9899:2011", "ISO C 2011",
-             LineComment | C99 | C11 | Digraphs | HexFloat)
+             LineComment | C99 | C11 | Digraphs | HexFloat | ZeroInitializer)
 LANGSTANDARD(iso9899_201x,
              "iso9899:201x", "ISO C 2011",
-             LineComment | C99 | C11 | Digraphs | HexFloat)
+             LineComment | C99 | C11 | Digraphs | HexFloat | ZeroInitializer)
 
 LANGSTANDARD(gnu11, "gnu11",
              "ISO C 2011 with GNU extensions",
-             LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
+             LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat | ZeroInitializer)
 LANGSTANDARD(gnu1x, "gnu1x",
              "ISO C 2011 with GNU extensions",
-             LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
+             LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat | ZeroInitializer)
 
 // C++ modes
 LANGSTANDARD(cxx98, "c++98",
Index: include/clang/Frontend/LangStandard.h
===================================================================
--- include/clang/Frontend/LangStandard.h
+++ include/clang/Frontend/LangStandard.h
@@ -29,7 +29,8 @@
   Digraphs = (1 << 8),
   GNUMode = (1 << 9),
   HexFloat = (1 << 10),
-  ImplicitInt = (1 << 11)
+  ImplicitInt = (1 << 11),
+  ZeroInitializer = (1 << 12)
 };
 
 }
@@ -91,6 +92,9 @@
   /// hasImplicitInt - Language allows variables to be typed as int implicitly.
   bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; }
 
+  /// hasZeroInitializer - Language considers { 0 } idiomatic.
+  bool hasZeroInitializer() const { return Flags & frontend::ZeroInitializer; }
+
   static const LangStandard &getLangStandardForKind(Kind K);
   static const LangStandard *getLangStandardForName(StringRef Name);
 };
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -111,6 +111,7 @@
 LANGOPT(GNUKeywords       , 1, 1, "GNU keywords")
 BENIGN_LANGOPT(ImplicitInt, 1, !C99 && !CPlusPlus, "C89 implicit 'int'")
 LANGOPT(Digraphs          , 1, 0, "digraphs")
+LANGOPT(ZeroInitializer   , 1, C99, "C's treatment of {0}")
 BENIGN_LANGOPT(HexFloats  , 1, C99, "C99 hexadecimal float constants")
 LANGOPT(CXXOperatorNames  , 1, 0, "C++ operator name keywords")
 LANGOPT(AppleKext         , 1, 0, "Apple kext support")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to