Improve the "braces around scalar init" warning to determine whether to warn
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 12 Feb 2015 01:50:05 +0000 (01:50 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 12 Feb 2015 01:50:05 +0000 (01:50 +0000)
based on whether "redundant" braces are ever reasonable as part of the
initialization of the entity, rather than whether the initialization is
"top-level". In passing, add a warning flag for it.

llvm-svn: 228896

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaInit.cpp
clang/test/CXX/drs/dr16xx.cpp
clang/test/Misc/warning-flags.c
clang/test/SemaCXX/cxx0x-initializer-constructor.cpp
clang/test/SemaCXX/cxx0x-initializer-references.cpp
clang/test/SemaCXX/cxx0x-initializer-scalars.cpp
clang/test/SemaCXX/cxx0x-return-init-list.cpp
clang/test/SemaCXX/cxx98-compat.cpp
clang/test/SemaCXX/microsoft-new-delete.cpp

index f14d709..d0949a2 100644 (file)
@@ -4171,9 +4171,10 @@ def warn_missing_field_initializers : Warning<
   "missing field %0 initializer">,
   InGroup<MissingFieldInitializers>, DefaultIgnore;
 def warn_braces_around_scalar_init : Warning<
-  "braces around scalar initializer">;
+  "braces around scalar initializer">, InGroup<DiagGroup<"braced-scalar-init">>;
 def ext_many_braces_around_scalar_init : ExtWarn<
-  "too many braces around scalar initializer">;
+  "too many braces around scalar initializer">,
+  InGroup<DiagGroup<"many-braces-around-scalar-init">>;
 def ext_complex_component_init : Extension<
   "complex initialization specifying real and imaginary components "
   "is an extension">, InGroup<DiagGroup<"complex-component-init">>;
index a25aada..dab0619 100644 (file)
@@ -754,6 +754,68 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
   }
 }
 
+/// Warn that \p Entity was of scalar type and was initialized by a
+/// single-element braced initializer list.
+static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
+                                 SourceRange Braces) {
+  // Don't warn during template instantiation. If the initialization was
+  // non-dependent, we warned during the initial parse; otherwise, the
+  // type might not be scalar in some uses of the template.
+  if (!S.ActiveTemplateInstantiations.empty())
+    return;
+
+  unsigned DiagID = 0;
+
+  switch (Entity.getKind()) {
+  case InitializedEntity::EK_VectorElement:
+  case InitializedEntity::EK_ComplexElement:
+  case InitializedEntity::EK_ArrayElement:
+  case InitializedEntity::EK_Parameter:
+  case InitializedEntity::EK_Parameter_CF_Audited:
+  case InitializedEntity::EK_Result:
+    // Extra braces here are suspicious.
+    DiagID = diag::warn_braces_around_scalar_init;
+    break;
+
+  case InitializedEntity::EK_Member:
+    // Warn on aggregate initialization but not on ctor init list or
+    // default member initializer.
+    if (Entity.getParent())
+      DiagID = diag::warn_braces_around_scalar_init;
+    break;
+
+  case InitializedEntity::EK_Variable:
+  case InitializedEntity::EK_LambdaCapture:
+    // No warning, might be direct-list-initialization.
+    // FIXME: Should we warn for copy-list-initialization in these cases?
+    break;
+
+  case InitializedEntity::EK_New:
+  case InitializedEntity::EK_Temporary:
+  case InitializedEntity::EK_CompoundLiteralInit:
+    // No warning, braces are part of the syntax of the underlying construct.
+    break;
+
+  case InitializedEntity::EK_RelatedResult:
+    // No warning, we already warned when initializing the result.
+    break;
+
+  case InitializedEntity::EK_Exception:
+  case InitializedEntity::EK_Base:
+  case InitializedEntity::EK_Delegating:
+  case InitializedEntity::EK_BlockElement:
+    llvm_unreachable("unexpected braced scalar init");
+  }
+
+  if (DiagID) {
+    S.Diag(Braces.getBegin(), DiagID)
+      << Braces
+      << FixItHint::CreateRemoval(Braces.getBegin())
+      << FixItHint::CreateRemoval(Braces.getEnd());
+  }
+}
+
+
 /// Check whether the initializer \p IList (that was written with explicit
 /// braces) can be used to initialize an object of type \p T.
 ///
@@ -829,12 +891,9 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
     }
   }
 
-  if (!VerifyOnly && T->isScalarType() && IList->getNumInits() == 1 &&
-      !TopLevelObject)
-    SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
-      << IList->getSourceRange()
-      << FixItHint::CreateRemoval(IList->getLocStart())
-      << FixItHint::CreateRemoval(IList->getLocEnd());
+  if (!VerifyOnly && T->isScalarType() &&
+      IList->getNumInits() == 1 && !isa<InitListExpr>(IList->getInit(0)))
+    warnBracedScalarInit(SemaRef, Entity, IList->getSourceRange());
 }
 
 void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
index cbbd0e9..ddb7d16 100644 (file)
@@ -29,7 +29,7 @@ namespace dr1631 {  // dr1631: 3.7 c++11
   void f(int, A);
 
   void test() {
-    f({0}, {{1}});
+    f({0}, {{1}}); // expected-warning {{braces around scalar init}}
   }
 
   namespace with_error {
index 74ab566..657b44d 100644 (file)
@@ -18,14 +18,13 @@ This test serves two purposes:
 
 The list of warnings below should NEVER grow.  It should gradually shrink to 0.
 
-CHECK: Warnings without flags (96):
+CHECK: Warnings without flags (94):
 CHECK-NEXT:   ext_excess_initializers
 CHECK-NEXT:   ext_excess_initializers_in_char_array_initializer
 CHECK-NEXT:   ext_expected_semi_decl_list
 CHECK-NEXT:   ext_explicit_specialization_storage_class
 CHECK-NEXT:   ext_implicit_lib_function_decl
 CHECK-NEXT:   ext_initializer_string_for_char_array_too_long
-CHECK-NEXT:   ext_many_braces_around_scalar_init
 CHECK-NEXT:   ext_missing_declspec
 CHECK-NEXT:   ext_missing_whitespace_after_macro_name
 CHECK-NEXT:   ext_new_paren_array_nonconst
@@ -50,7 +49,6 @@ CHECK-NEXT:   warn_anon_bitfield_width_exceeds_type_size
 CHECK-NEXT:   warn_arcmt_nsalloc_realloc
 CHECK-NEXT:   warn_asm_label_on_auto_decl
 CHECK-NEXT:   warn_bitfield_width_exceeds_type_size
-CHECK-NEXT:   warn_braces_around_scalar_init
 CHECK-NEXT:   warn_c_kext
 CHECK-NEXT:   warn_call_to_pure_virtual_member_function_from_ctor_dtor
 CHECK-NEXT:   warn_call_wrong_number_of_arguments
index 0cd5aa7..6202bf6 100644 (file)
@@ -142,6 +142,7 @@ namespace objects {
 
     one ov2(int);
     two ov2(F<3>);
+    // expected-warning@+1 {{braces around scalar initializer}}
     static_assert(sizeof(ov2({1})) == sizeof(one), "bad overload"); // list -> int ranks as identity
     static_assert(sizeof(ov2({1, 2, 3})) == sizeof(two), "bad overload"); // list -> F only viable
   }
index dda68a3..f9164fb 100644 (file)
@@ -110,7 +110,7 @@ namespace inner_init {
   struct D { C &&r; };
   D d1 { 0 }; // ok, 0 implicitly converts to C
   D d2 { { 0 } }; // ok, { 0 } calls C(0)
-  D d3 { { { 0 } } }; // ok, { { 0 } } calls C({ 0 })
+  D d3 { { { 0 } } }; // ok, { { 0 } } calls C({ 0 }), expected-warning {{braces around scalar init}}
   D d4 { { { { 0 } } } }; // expected-error {{no matching constructor for initialization of 'inner_init::C &&'}}
 
   struct E { explicit E(int); }; // expected-note 2{{here}}
index 1475dcf..c9d5ffd 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -pedantic-errors
 
 struct one { char c[1]; };
 struct two { char c[2]; };
@@ -55,7 +55,7 @@ namespace integral {
     int ar[10];
     (void) ar[{1}]; // expected-error {{array subscript is not an integer}}
 
-    return {1};
+    return {1}; // expected-warning {{braces around scalar init}}
   }
 
   void inline_init() {
@@ -70,15 +70,15 @@ namespace integral {
 
   void function_call() {
     void takes_int(int);
-    takes_int({1});
+    takes_int({1}); // expected-warning {{braces around scalar init}}
   }
 
   void overloaded_call() {
     one overloaded(int);
     two overloaded(double);
 
-    static_assert(sizeof(overloaded({0})) == sizeof(one), "bad overload");
-    static_assert(sizeof(overloaded({0.0})) == sizeof(two), "bad overload");
+    static_assert(sizeof(overloaded({0})) == sizeof(one), "bad overload"); // expected-warning {{braces around scalar init}}
+    static_assert(sizeof(overloaded({0.0})) == sizeof(two), "bad overload"); // expected-warning {{braces around scalar init}}
 
     void ambiguous(int, double); // expected-note {{candidate}}
     void ambiguous(double, int); // expected-note {{candidate}}
index da83271..84bd89b 100644 (file)
@@ -4,7 +4,7 @@
 // required for libstdc++ 4.5) is supported in C++98.
 
 int test0(int i) {
-  return { i }; // expected-warning{{generalized initializer lists are a C++11 extension}}
+  return { i }; // expected-warning{{generalized initializer lists are a C++11 extension}} expected-warning {{scalar}}
 }
 
 template<typename T, typename U>
index 029e909..4227272 100644 (file)
@@ -74,10 +74,10 @@ int InitList(int i = {}) { // expected-warning {{generalized initializer lists a
   InitListCtor ilc = { true, false }; // expected-warning {{initialization of initializer_list object is incompatible with C++98}}
   const int &r = { 0 }; // expected-warning {{reference initialized from initializer list is incompatible with C++98}}
   struct { int a; const int &r; } rr = { 0, {0} }; // expected-warning {{reference initialized from initializer list is incompatible with C++98}}
-  return { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}}
+  return { 0 }; // expected-warning {{generalized initializer lists are incompatible with C++98}} expected-warning {{scalar}}
 }
 struct DelayedDefaultArgumentParseInitList {
-  void f(int i = {1}) { // expected-warning {{generalized initializer lists are incompatible with C++98}}
+  void f(int i = {1}) { // expected-warning {{generalized initializer lists are incompatible with C++98}} expected-warning {{scalar}}
   }
 };
 
index 6c9be22..b929e61 100644 (file)
@@ -31,4 +31,4 @@ struct explicit_ctor_tag {} ect;
 void *operator new[](size_t, explicit_ctor_tag, explicit_ctor);
 void *operator new(size_t, explicit_ctor_tag, int);
 void *t = new (ect, 0) int[4];
-void *u = new (ect, {0}) int[4];
+void *u = new (ect, {0}) int[4]; // expected-warning {{braces around scalar init}}