r286721 - Use descriptive message if list initializer is incorrectly parenthesized.

Serge Pavlov via cfe-commits cfe-commits at lists.llvm.org
Sat Nov 12 07:38:56 PST 2016


Author: sepavloff
Date: Sat Nov 12 09:38:55 2016
New Revision: 286721

URL: http://llvm.org/viewvc/llvm-project?rev=286721&view=rev
Log:
Use descriptive message if list initializer is incorrectly parenthesized.

If initializer contains parentheses around braced list where it is not allowed,
as in construct int({0}), clang issued message like `functional-style cast
from 'void' to 'int' is not allowed`, which does not help much. Both gcc and
msvc issue message `list-initializer for non-class type must not be
parenthesized`, which is more descriptive. This change implements similar
message for clang.

Differential Revision: https://reviews.llvm.org/D25816

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
    cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=286721&r1=286720&r2=286721&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Nov 12 09:38:55 2016
@@ -1780,6 +1780,8 @@ def note_uninit_fixit_remove_cond : Note
   "remove the %select{'%1' if its condition|condition if it}0 "
   "is always %select{false|true}2">;
 def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
+def err_list_init_in_parens : Error<"list-initializer for non-class type %0 "
+  "must not be parenthesized">;
 
 def warn_unsequenced_mod_mod : Warning<
   "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=286721&r1=286720&r2=286721&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Nov 12 09:38:55 2016
@@ -1796,6 +1796,8 @@ public:
                             bool TypeMayContainAuto);
   void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
   void ActOnInitializerError(Decl *Dcl);
+  bool canInitializeWithParenthesizedList(QualType TargetType);
+
   void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc);
   void ActOnCXXForRangeDecl(Decl *D);
   StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=286721&r1=286720&r2=286721&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Nov 12 09:38:55 2016
@@ -9865,6 +9865,18 @@ void Sema::AddInitializerToDecl(Decl *Re
   // Perform the initialization.
   ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
   if (!VDecl->isInvalidDecl()) {
+    // Handle errors like: int a({0})
+    if (CXXDirectInit && CXXDirectInit->getNumExprs() == 1 &&
+        !canInitializeWithParenthesizedList(VDecl->getType()))
+      if (auto IList = dyn_cast<InitListExpr>(CXXDirectInit->getExpr(0))) {
+        Diag(VDecl->getLocation(), diag::err_list_init_in_parens)
+            << VDecl->getType() << CXXDirectInit->getSourceRange()
+            << FixItHint::CreateRemoval(CXXDirectInit->getLocStart())
+            << FixItHint::CreateRemoval(CXXDirectInit->getLocEnd());
+        Init = IList;
+        CXXDirectInit = nullptr;
+      }
+
     InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
     InitializationKind Kind =
         DirectInit
@@ -10171,6 +10183,18 @@ void Sema::ActOnInitializerError(Decl *D
   // though.
 }
 
+/// Checks if an object of the given type can be initialized with parenthesized
+/// init-list.
+///
+/// \param TargetType Type of object being initialized.
+///
+/// The function is used to detect wrong initializations, such as 'int({0})'.
+///
+bool Sema::canInitializeWithParenthesizedList(QualType TargetType) {
+  return TargetType->isDependentType() || TargetType->isRecordType() ||
+         TargetType->getContainedAutoType();
+}
+
 void Sema::ActOnUninitializedDecl(Decl *RealDecl,
                                   bool TypeMayContainAuto) {
   // If there is no declaration, there was an error parsing it. Just ignore it.

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=286721&r1=286720&r2=286721&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sat Nov 12 09:38:55 2016
@@ -1221,6 +1221,17 @@ Sema::ActOnCXXTypeConstructExpr(ParsedTy
   if (!TInfo)
     TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation());
 
+  // Handle errors like: int({0})
+  if (exprs.size() == 1 && !canInitializeWithParenthesizedList(Ty) &&
+      LParenLoc.isValid() && RParenLoc.isValid())
+    if (auto IList = dyn_cast<InitListExpr>(exprs[0])) {
+      Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens)
+          << Ty << IList->getSourceRange()
+          << FixItHint::CreateRemoval(LParenLoc)
+          << FixItHint::CreateRemoval(RParenLoc);
+      LParenLoc = RParenLoc = SourceLocation();
+    }
+
   auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc);
   // Avoid creating a non-type-dependent expression that contains typos.
   // Non-type-dependent expressions are liable to be discarded without
@@ -1562,8 +1573,20 @@ Sema::ActOnCXXNew(SourceLocation StartLo
     return ExprError();
 
   SourceRange DirectInitRange;
-  if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
+  if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
     DirectInitRange = List->getSourceRange();
+    // Handle errors like: new int a({0})
+    if (List->getNumExprs() == 1 &&
+        !canInitializeWithParenthesizedList(AllocType))
+      if (auto IList = dyn_cast<InitListExpr>(List->getExpr(0))) {
+        Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens)
+            << AllocType << List->getSourceRange()
+            << FixItHint::CreateRemoval(List->getLocStart())
+            << FixItHint::CreateRemoval(List->getLocEnd());
+        DirectInitRange = SourceRange();
+        Initializer = IList;
+      }
+  }
 
   return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal,
                      PlacementLParen,

Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp?rev=286721&r1=286720&r2=286721&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp Sat Nov 12 09:38:55 2016
@@ -72,10 +72,9 @@ namespace reference {
   }
 
   void edge_cases() {
-    // FIXME: very poor error message
-    int const &b({0}); // expected-error {{could not bind}}
+    int const &b({0}); // expected-error {{list-initializer for non-class type 'const int &' must not be parenthesized}}
+    const int (&arr)[3] ({1, 2, 3}); // expected-error {{list-initializer for non-class type 'const int (&)[3]' must not be parenthesized}}
   }
-
 }
 
 namespace PR12182 {

Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp?rev=286721&r1=286720&r2=286721&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp Sat Nov 12 09:38:55 2016
@@ -91,10 +91,23 @@ namespace integral {
   }
 
   void edge_cases() {
-    // FIXME: very poor error message
-    int a({0}); // expected-error {{cannot initialize}}
-    (void) int({0}); // expected-error {{functional-style cast}}
-    new int({0});  // expected-error {{cannot initialize}}
+    int a({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
+    (void) int({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
+    new int({0});  // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
+
+    int *b({0});  // expected-error {{list-initializer for non-class type 'int *' must not be parenthesized}}
+    typedef int *intptr;
+    int *c = intptr({0});  // expected-error {{list-initializer for non-class type 'intptr' (aka 'int *') must not be parenthesized}}
+  }
+
+  template<typename T> void dependent_edge_cases() {
+    T a({0});
+    (void) T({0});
+    new T({0});
+
+    T *b({0});
+    typedef T *tptr;
+    T *c = tptr({0});
   }
 
   void default_argument(int i = {}) {




More information about the cfe-commits mailing list