]> granicus.if.org Git - clang/commitdiff
[c++1z] Require an initializer for deduced class template specialization types.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 10 Feb 2017 21:40:29 +0000 (21:40 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 10 Feb 2017 21:40:29 +0000 (21:40 +0000)
It's actually meaningful and useful to allow such variables to have no
initializer, but we are strictly following the standard here until the C++
committee reaches consensus on allowing this.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@294785 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp
test/Parser/cxx1z-class-template-argument-deduction.cpp
test/SemaCXX/cxx1y-variable-templates_top_level.cpp

index 6bf33897d5d590eee8f22456e555c1d2f7938e76..e64fed77edd11b747550a08bfd5c1315d3f9915a 100644 (file)
@@ -1893,7 +1893,7 @@ def err_dependent_deduced_tst : Error<
 def err_auto_not_allowed_var_inst : Error<
   "'auto' variable template instantiation is not allowed">;
 def err_auto_var_requires_init : Error<
-  "declaration of variable %0 with type %1 requires an initializer">;
+  "declaration of variable %0 with deduced type %1 requires an initializer">;
 def err_auto_new_requires_ctor_arg : Error<
   "new expression for type %0 requires a constructor argument">;
 def err_auto_new_list_init : Error<
index 2a082fc775b7fd6234a0f3cd8694ab2be6cff350..17d58b156bab186385acf20351cea1cbc7b8b036 100644 (file)
@@ -9816,7 +9816,15 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
   DeducedType *Deduced = Type->getContainedDeducedType();
   assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type");
 
-  ArrayRef<Expr*> DeduceInits = Init ? ArrayRef<Expr*>(Init) : None;
+  // C++11 [dcl.spec.auto]p3
+  if (!Init) {
+    assert(VDecl && "no init for init capture deduction?");
+    Diag(VDecl->getLocation(), diag::err_auto_var_requires_init)
+      << VDecl->getDeclName() << Type;
+    return QualType();
+  }
+
+  ArrayRef<Expr*> DeduceInits = Init;
   if (DirectInit) {
     if (auto *PL = dyn_cast_or_null<ParenListExpr>(Init))
       DeduceInits = PL->exprs();
@@ -9833,14 +9841,6 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
                                                        InitsCopy);
   }
 
-  // C++11 [dcl.spec.auto]p3
-  if (!Init) {
-    assert(VDecl && "no init for init capture deduction?");
-    Diag(VDecl->getLocation(), diag::err_auto_var_requires_init)
-      << VDecl->getDeclName() << Type;
-    return QualType();
-  }
-
   if (DirectInit) {
     if (auto *IL = dyn_cast<InitListExpr>(Init))
       DeduceInits = IL->inits();
index eb751517e2f2a206abc3aa6309b83c958b5d02ea..fce5795daecb117f8428751998992e474d6b1700 100644 (file)
@@ -9,9 +9,9 @@ void f() {
 }
 
 void g() {
-  decltype(auto) a; // expected-error{{declaration of variable 'a' with type 'decltype(auto)' requires an initializer}}
+  decltype(auto) a; // expected-error{{declaration of variable 'a' with deduced type 'decltype(auto)' requires an initializer}}
   
-  decltype(auto) *b; // expected-error{{cannot form pointer to 'decltype(auto)'}} expected-error{{declaration of variable 'b' with type 'decltype(auto) *' requires an initializer}}
+  decltype(auto) *b; // expected-error{{cannot form pointer to 'decltype(auto)'}} expected-error{{declaration of variable 'b' with deduced type 'decltype(auto) *' requires an initializer}}
 
   if (decltype(auto) b) {} // expected-error {{must have an initializer}}
   for (;decltype(auto) b;) {} // expected-error {{must have an initializer}}
index e91cacf10466ca7eef587952c4d4ed21b8996be1..c38bd7a84d4711fdeeed504a79d1a7e70dfeb96f 100644 (file)
@@ -9,9 +9,9 @@ void f() {
 }
 
 void g() {
-  auto a; // expected-error{{declaration of variable 'a' with type 'auto' requires an initializer}}
+  auto a; // expected-error{{declaration of variable 'a' with deduced type 'auto' requires an initializer}}
   
-  auto *b; // expected-error{{declaration of variable 'b' with type 'auto *' requires an initializer}}
+  auto *b; // expected-error{{declaration of variable 'b' with deduced type 'auto *' requires an initializer}}
 
   if (auto b) {} // expected-error {{must have an initializer}}
   for (;auto b;) {} // expected-error {{must have an initializer}}
index 46c874f605cbf27d6c64f23fdd2a4612c003ca42..bf1b3092e08e86a2443c324769dd38a706cc2ac4 100644 (file)
@@ -36,7 +36,7 @@ class X {
 };
 
 struct S {
-  static const auto a; // expected-error {{declaration of variable 'a' with type 'const auto' requires an initializer}}
+  static const auto a; // expected-error {{declaration of variable 'a' with deduced type 'const auto' requires an initializer}}
   static const auto b = 0;
   static const int c;
 };
index 88197999cd9054f938940b66bf0d0afe5daefb3b..cfb9a61f1ac42b5155d8fe9e15e80560f89bdfcf 100644 (file)
@@ -5,8 +5,14 @@ A() -> A<int>;
 A(int) -> A<char>;
 
 static constexpr inline const volatile A a = {}; // ok, specifiers are permitted
-A b; // FIXME: An initializer is required
+// FIXME: There isn't really a good reason to reject this.
+A b; // expected-error {{requires an initializer}}
 A c [[]] {};
 
 A d = {}, e = {};
 A f(0), g{}; // expected-error {{template arguments deduced as 'A<char>' in declaration of 'f' and deduced as 'A<int>' in declaration of 'g'}}
+
+struct B {
+  static A a; // expected-error {{requires an initializer}}
+};
+extern A x; // expected-error {{requires an initializer}}
index 10be123eb05524f86eb18f6b1b01818c395d3c8f..ab8c867f60a040fae6eecf4d0c287620098c5eee 100644 (file)
@@ -52,7 +52,7 @@ struct member {
 
   operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}}
 
-  static A x; // FIXME: We deduce A<int> from the initializer despite this not being a definition!
+  static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}}
   static constexpr A y = 0;
 };
 
@@ -127,7 +127,7 @@ namespace decl {
 
   auto k() -> A; // expected-error{{requires template arguments}}
 
-  A a; // FIXME: This is (technically) syntactically invalid.
+  A a; // expected-error {{declaration of variable 'a' with deduced type 'A' requires an initializer}}
   A b = 0;
   const A c = 0;
   A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
index 367f67bf5fa8f04c11eda0cc22c7278b037aa0a8..b4963646838cb607895add56e69cb3367d3138d2 100644 (file)
@@ -102,7 +102,7 @@ namespace odr_tmpl {
     template<typename T> extern int v;    // expected-error {{redeclaration of 'v' with a different type: 'int' vs 'T'}}
 
 #ifndef PRECXX11
-    template<typename T> extern auto v;   // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}}
+    template<typename T> extern auto v;   // expected-error {{declaration of variable 'v' with deduced type 'auto' requires an initializer}}
 #endif
 
     template<typename T> T var = T();     // expected-note {{previous definition is here}}
@@ -111,7 +111,7 @@ namespace odr_tmpl {
 
 #ifndef PRECXX11
   namespace pvt_auto {
-    template<typename T> auto v0; // expected-error {{declaration of variable 'v0' with type 'auto' requires an initializer}}
+    template<typename T> auto v0; // expected-error {{declaration of variable 'v0' with deduced type 'auto' requires an initializer}}
     template<typename T> auto v1 = T();  // expected-note {{previous definition is here}}
     template<typename T> int v1;   // expected-error {{redefinition of 'v1' with a different type: 'int' vs 'auto'}}
     template<typename T> auto v2 = T();  // expected-note {{previous definition is here}}
@@ -119,7 +119,7 @@ namespace odr_tmpl {
     template<typename T> auto v3 = T();   // expected-note {{previous definition is here}}
     template<typename T> extern T v3;     // expected-error {{redeclaration of 'v3' with a different type: 'T' vs 'auto'}}
     template<typename T> auto v4 = T();
-    template<typename T> extern auto v4;   // expected-error {{declaration of variable 'v4' with type 'auto' requires an initializer}}
+    template<typename T> extern auto v4;   // expected-error {{declaration of variable 'v4' with deduced type 'auto' requires an initializer}}
   }
 #endif