tbaeder created this revision.
tbaeder added a reviewer: aaron.ballman.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Consider:

  constexpr int a;

the error message for this is currently:

  error: default initialization of an object of const type 'const int'
  constexpr int a;
                ^
                  = 0

which makes very little sense to me. With this patch, the output is instead:

  error: constexpr variable 'a' must be initialized by a constant expression
  constexpr int a;
                ^
                  = 0

which is much better. Tells the user exactly what is missing.

For

  constexpr int a[];

before this patch, the output is:

  error: definition of variable with array type needs an explicit size or an 
initializer
  constexpr int a[];
                ^

The error message is not even true in this case, since _only_ passing a size 
won't work. It must be initialized by a constant expression, so now the error 
message is:

  error: constexpr variable 'a' must be initialized by a constant expression
  constexpr int a[];
                ^

and a fixit hint if a size was provided:

  error: constexpr variable 'a' must be initialized by a constant expression
  constexpr int a[2];
                ^
                     = {}

(not sure about that part)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131662

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaFixItUtils.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
  clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
  clang/test/SemaCXX/constant-expression-cxx11.cpp

Index: clang/test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -27,6 +27,10 @@
   constexpr int zero() const { return 0; }
 };
 
+constexpr int arr[]; // expected-error {{constexpr variable 'arr' must be initialized by a constant expression}}
+constexpr int arr2[2]; // expected-error {{constexpr variable 'arr2' must be initialized by a constant expression}}
+constexpr int arr3[2] = {};
+
 namespace DerivedToVBaseCast {
 
   struct U { int n; };
@@ -1298,7 +1302,7 @@
   void f() {
     extern constexpr int i; // expected-error {{constexpr variable declaration must be a definition}}
     constexpr int j = 0;
-    constexpr int k; // expected-error {{default initialization of an object of const type}}
+    constexpr int k; // expected-error {{constexpr variable 'k' must be initialized by a constant expression}}
   }
 
   extern const int q;
Index: clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
+++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
@@ -18,7 +18,7 @@
 
 // A variable declaration which uses the constexpr specifier shall have an
 // initializer and shall be initialized by a constant expression.
-constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}}
+constexpr int ni1; // expected-error {{constexpr variable 'ni1' must be initialized by a constant expression}}
 constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}}
 constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}}
 
Index: clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -37,7 +37,7 @@
 #if __cplusplus <= 201402L && !defined(MS_ABI)
   // expected-error@-2 {{requires an initializer}}
 #else
-  // expected-error@-4 {{default initialization of an object of const}}
+  // expected-error@-4 {{constexpr variable 'mi2' must be initialized by a constant expression}}
 #endif
   mutable constexpr int mi3 = 3; // expected-error-re {{non-static data member cannot be constexpr{{$}}}} expected-error {{'mutable' and 'const' cannot be mixed}}
 };
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -8053,19 +8053,29 @@
     return ExprError();
   }
   if (!ZeroInitializationFixit.empty()) {
-    unsigned DiagID = diag::err_default_init_const;
-    if (Decl *D = Entity.getDecl())
-      if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>())
-        DiagID = diag::ext_default_init_const;
+    const Decl *D = Entity.getDecl();
+    const VarDecl *VD = dyn_cast_or_null<VarDecl>(D);
+    QualType DestType = Entity.getType();
 
     // The initialization would have succeeded with this fixit. Since the fixit
     // is on the error, we need to build a valid AST in this case, so this isn't
     // handled in the Failed() branch above.
-    QualType DestType = Entity.getType();
-    S.Diag(Kind.getLocation(), DiagID)
-        << DestType << (bool)DestType->getAs<RecordType>()
-        << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
-                                      ZeroInitializationFixit);
+    if (!DestType->getAs<RecordType>() && VD && VD->isConstexpr()) {
+      // Use a more useful diagnostic for constexpr variables.
+      S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init)
+          << VD
+          << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
+                                        ZeroInitializationFixit);
+    } else {
+      unsigned DiagID = diag::err_default_init_const;
+      if (S.getLangOpts().MSVCCompat && D && D->hasAttr<SelectAnyAttr>())
+        DiagID = diag::ext_default_init_const;
+
+      S.Diag(Kind.getLocation(), DiagID)
+          << DestType << (bool)DestType->getAs<RecordType>()
+          << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
+                                        ZeroInitializationFixit);
+    }
   }
 
   if (getKind() == DependentSequence) {
Index: clang/lib/Sema/SemaFixItUtils.cpp
===================================================================
--- clang/lib/Sema/SemaFixItUtils.cpp
+++ clang/lib/Sema/SemaFixItUtils.cpp
@@ -205,6 +205,10 @@
     return s;
   }
 
+  if (T->isArrayType()) {
+    return " = {}";
+  }
+
   const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
   if (!RD || !RD->hasDefinition())
     return std::string();
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -13363,8 +13363,12 @@
     // Provide a specific diagnostic for uninitialized variable
     // definitions with incomplete array type.
     if (Type->isIncompleteArrayType()) {
-      Diag(Var->getLocation(),
-           diag::err_typecheck_incomplete_array_needs_initializer);
+      if (Var->isConstexpr())
+        Diag(Var->getLocation(), diag::err_constexpr_var_requires_const_init)
+            << Var;
+      else
+        Diag(Var->getLocation(),
+             diag::err_typecheck_incomplete_array_needs_initializer);
       Var->setInvalidDecl();
       return;
     }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to