From: Zhihao Yuan Date: Sat, 24 Mar 2018 04:32:11 +0000 (+0000) Subject: [C++17] Fix class template argument deduction for default constructors without an... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b6f2fc5248bcd5628dfb8dcb10fe820b9f74c18d;p=clang [C++17] Fix class template argument deduction for default constructors without an initializer Summary: As the title says, this makes following code compile: ``` template struct Foo {}; Foo() -> Foo; Foo f; // ok ``` Thanks Nicolas Lesser for coining the fix. Reviewers: rsmith, lichray Reviewed By: rsmith, lichray Subscribers: lichray, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D38216 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@328409 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6319e4b34c..d583646a38 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -10396,12 +10396,22 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, // 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(); + + // Except for class argument deduction, and then for an initializing + // declaration only, i.e. no static at class scope or extern. + if (!isa(Deduced) || + VDecl->hasExternalStorage() || + VDecl->isStaticDataMember()) { + Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) + << VDecl->getDeclName() << Type; + return QualType(); + } } - ArrayRef DeduceInits = Init; + ArrayRef DeduceInits; + if (Init) + DeduceInits = Init; + if (DirectInit) { if (auto *PL = dyn_cast_or_null(Init)) DeduceInits = PL->exprs(); diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp index cfb9a61f1a..96be58f8eb 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ A() -> A; A(int) -> A; static constexpr inline const volatile A a = {}; // ok, specifiers are permitted -// FIXME: There isn't really a good reason to reject this. -A b; // expected-error {{requires an initializer}} +A b; A c [[]] {}; A d = {}, e = {}; @@ -16,3 +15,5 @@ struct B { static A a; // expected-error {{requires an initializer}} }; extern A x; // expected-error {{requires an initializer}} +static A y; + diff --git a/test/Parser/cxx1z-class-template-argument-deduction.cpp b/test/Parser/cxx1z-class-template-argument-deduction.cpp index bf1d004c8d..532c893f21 100644 --- a/test/Parser/cxx1z-class-template-argument-deduction.cpp +++ b/test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -137,7 +137,6 @@ namespace expr { (void)A{n}; (void)new A(n); (void)new A{n}; - // FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -150,7 +149,7 @@ namespace decl { auto k() -> A; // expected-error{{requires template arguments}} - A a; // expected-error {{declaration of variable 'a' with deduced type 'A' requires an initializer}} + A a; A b = 0; const A c = 0; A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}