[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
This revision was automatically updated to reflect the committed changes. Closed by commit rC328409: [C++17] Fix class template argument deduction for default constructors without… (authored by lichray, committed by ). Repository: rC Clang https://reviews.llvm.org/D38216 Files: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp test/Parser/cxx1z-class-template-argument-deduction.cpp Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 @@ static A a; // expected-error {{requires an initializer}} }; extern A x; // expected-error {{requires an initializer}} +static A y; + Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -137,7 +137,6 @@ (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 @@ 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}} Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10396,12 +10396,22 @@ // 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(); +} } - ArrayRefDeduceInits = Init; + ArrayRef DeduceInits; + if (Init) +DeduceInits = Init; + if (DirectInit) { if (auto *PL = dyn_cast_or_null(Init)) DeduceInits = PL->exprs(); Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 @@ static A a; // expected-error {{requires an initializer}} }; extern A x; // expected-error {{requires an initializer}} +static A y; + Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -137,7 +137,6 @@ (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 @@ 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}} Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10396,12 +10396,22 @@ // 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.
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
rsmith accepted this revision. rsmith added inline comments. This revision is now accepted and ready to land. Comment at: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp:17 }; extern A x; // expected-error {{requires an initializer}} +static A y; The diagnostic we produce in this case is not very good. The problem is not that the declaration requires an initializer (how can a forward declaration like this require an initializer?), instead the problem is that type deduction is only possible for the initializing declaration of a variable. https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
Rakete updated this revision to Diff 138862. Rakete added a comment. @lichray Ok done :) Thanks for reviewing https://reviews.llvm.org/D38216 Files: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp test/Parser/cxx1z-class-template-argument-deduction.cpp Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -137,7 +137,6 @@ (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 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 @@ static A a; // expected-error {{requires an initializer}} }; extern A x; // expected-error {{requires an initializer}} +static A y; + Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10396,12 +10396,22 @@ // 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(); +} } - ArrayRefDeduceInits = Init; + ArrayRef DeduceInits; + if (Init) +DeduceInits = Init; + if (DirectInit) { if (auto *PL = dyn_cast_or_null(Init)) DeduceInits = PL->exprs(); Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -137,7 +137,6 @@ (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 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 @@ static A a; // expected-error {{requires an initializer}} }; extern A x; // expected-error {{requires an initializer}} +static A y; + Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10396,12 +10396,22 @@ // 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()) { +
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
lichray added a comment. LGTM Comment at: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp:17 }; extern A x; // expected-error {{requires an initializer}} Please add one more test to the end of the file saying ``` static A y; ``` as a remainder to the readers. https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
Rakete updated this revision to Diff 138187. Rakete added a comment. Addressed review comments :) Thanks! https://reviews.llvm.org/D38216 Files: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp test/Parser/cxx1z-class-template-argument-deduction.cpp Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -137,7 +137,6 @@ (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 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 = {}; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10395,12 +10395,22 @@ // 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(); +} } - ArrayRefDeduceInits = Init; + ArrayRef DeduceInits; + if (Init) +DeduceInits = Init; + if (DirectInit) { if (auto *PL = dyn_cast_or_null(Init)) DeduceInits = PL->exprs(); Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -137,7 +137,6 @@ (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 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 = {}; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10395,12 +10395,22 @@ // 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))
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
rsmith requested changes to this revision. rsmith added a comment. This revision now requires changes to proceed. Per [dcl.type.class.deduct]p1, only the initializing declaration of a variable can use a placeholder type. The existing diagnostic was correct in many of the modified cases. Comment at: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp:15 struct B { - static A a; // expected-error {{requires an initializer}} + static A a; }; This should be ill-formed: this is not the initializing declaration of `B::a`. Comment at: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp:17 }; -extern A x; // expected-error {{requires an initializer}} +extern A x; Likewise, this should remain ill-formed. Comment at: test/Parser/cxx1z-class-template-argument-deduction.cpp:55 - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; Likewise. https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
Rakete updated this revision to Diff 128662. Rakete marked an inline comment as done. Rakete added a comment. Rebased + friendly 2018 ping https://reviews.llvm.org/D38216 Files: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp test/Parser/cxx1z-class-template-argument-deduction.cpp Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,14 +5,13 @@ 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 = {}; A f(0), g{}; // expected-error {{template arguments deduced as 'A' in declaration of 'f' and deduced as 'A' in declaration of 'g'}} struct B { - static A a; // expected-error {{requires an initializer}} + static A a; }; -extern A x; // expected-error {{requires an initializer}} +extern A x; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10053,14 +10053,18 @@ assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); // C++11 [dcl.spec.auto]p3 - if (!Init) { + // Except for class argument deduction. + if (!Init && !isa(Deduced)) { assert(VDecl && "no init for init capture deduction?"); Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) << VDecl->getDeclName() << Type; return QualType(); } - ArrayRefDeduceInits = Init; + ArrayRef DeduceInits; + if (Init) +DeduceInits = Init; + if (DirectInit) { if (auto *PL = dyn_cast_or_null(Init)) DeduceInits = PL->exprs(); Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,14 +5,13 @@ 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 = {}; A f(0), g{}; // expected-error {{template arguments deduced as 'A' in declaration of 'f' and deduced as 'A' in declaration of 'g'}} struct B { - static A a; // expected-error {{requires an initializer}} + static A a; }; -extern A x; // expected-error {{requires an
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
rsmith added a comment. In https://reviews.llvm.org/D38216#924039, @lichray wrote: > So gcc got this wrong? > > https://wandbox.org/permlink/RVApvaca1ebUfInn Yes, the declaration `extern A a;` in that example is ill-formed. https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
lichray added a comment. In https://reviews.llvm.org/D38216#923580, @rsmith wrote: > That's almost right, but not all `extern` declarations are disallowed. (An > `extern` declaration is still a defining declaration if it has an > initializer.) Good to know, thanks. So gcc got this wrong? https://wandbox.org/permlink/RVApvaca1ebUfInn https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
Rakete updated this revision to Diff 122708. Rakete added a comment. Made `DeduceInits` empty instead of a workaround somewhere else. Is it still ok, @rsmith ? https://reviews.llvm.org/D38216 Files: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp test/Parser/cxx1z-class-template-argument-deduction.cpp Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 = {}; @@ -13,6 +12,6 @@ A f(0), g{}; // expected-error {{template arguments deduced as 'A' in declaration of 'f' and deduced as 'A' in declaration of 'g'}} struct B { - static A a; // expected-error {{requires an initializer}} + static A a; }; -extern A x; // expected-error {{requires an initializer}} +extern A x; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10182,7 +10182,8 @@ assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); // C++11 [dcl.spec.auto]p3 - if (!Init) { + // Except for class argument deduction. + if (!Init && !isa(Deduced)) { assert(VDecl && "no init for init capture deduction?"); Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) << VDecl->getDeclName() << Type; @@ -10189,7 +10190,10 @@ return QualType(); } - ArrayRefDeduceInits = Init; + ArrayRef DeduceInits; + if (Init) +DeduceInits = Init; + if (DirectInit) { if (auto *PL = dyn_cast_or_null(Init)) DeduceInits = PL->exprs(); Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 = {}; @@ -13,6 +12,6 @@ A f(0), g{}; // expected-error {{template arguments deduced as 'A' in declaration of 'f' and deduced as 'A' in declaration of 'g'}} struct B { - static A a; // expected-error {{requires an
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
rsmith added a comment. In https://reviews.llvm.org/D38216#922768, @lichray wrote: > So deducing from default initialization is indeed allowed, but `extern` > could be interpreted as outlawed because similar to the case of non- > inline static data member, where the declaration doesn't give **the** > initialization of that variable. @rsmith, comments? That's almost right, but not all `extern` declarations are disallowed. (An `extern` declaration is still a defining declaration if it has an initializer.) Comment at: lib/Sema/SemaDecl.cpp:10208 +return DeduceTemplateSpecializationFromInitializer( + TSI, Entity, Kind, Init ? InitsCopy : MutableArrayRef()); } Please put this `?:` expression into the declaration of `DeduceInits` instead of here. (We should build an empty list instead of a list of one null pointer when there is no init.) https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
lichray added a comment. In https://reviews.llvm.org/D38216#922709, @Rakete wrote: > @lichray Isn't [dcl.type.auto.deduct] only for `auto` and `decltype(auto)`? Sorry, reasoned on a confusingly similar part... Here is updated information: > 10.1.7.5 [dcl.type.class.deduct] > If a placeholder for a deduced class type appears as a decl-specifier in > the decl-specifier-seq of an initializing declaration (11.6) of a variable, > [...]. > 11.6 [dcl.init]/22 > A declaration that specifies the initialization of a variable, whether from > an explicit initializer or by default initialization, is called the > initializing > declaration of that variable. [ Note: In most cases this is the defining > declaration (6.1) of the variable, but the initializing declaration of a non- > inline static data member (12.2.3.2) might be the declaration within the > class definition and not the definition at namespace scope. —end note ] So deducing from default initialization is indeed allowed, but `extern` could be interpreted as outlawed because similar to the case of non- inline static data member, where the declaration doesn't give **the** initialization of that variable. @rsmith, comments? https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
Rakete added a comment. @lichray Isn't [dcl.type.auto.deduct] only for `auto` and `decltype(auto)`? Class template argument deduction is in [dcl.type.class.deduct], which doesn't seem to disallow declarations without an initializer. About that `extern` business, yes that's indeed counter intuitive and weird. Couldn't find anything in the standard prohibiting this though, but I'm not so good at that either. https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
lichray added a comment. The standard hasn't allowed deducing any placeholder type without an initializer (10.1.7.4.1 [dcl.type.auto.deduct]/2) yet. It's unclear to me what extern A x; wants to archive. Usually when people writing `extern` then expect an initializer to appear somewhere else, but with this declaration, defining A x = ...; later may fail by resolving to a different type, which feels... interesting. https://reviews.llvm.org/D38216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
Rakete updated this revision to Diff 122576. Rakete added a comment. Slight change + rebased + friendly ping :) https://reviews.llvm.org/D38216 Files: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp test/Parser/cxx1z-class-template-argument-deduction.cpp Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 = {}; @@ -13,6 +12,6 @@ A f(0), g{}; // expected-error {{template arguments deduced as 'A' in declaration of 'f' and deduced as 'A' in declaration of 'g'}} struct B { - static A a; // expected-error {{requires an initializer}} + static A a; }; -extern A x; // expected-error {{requires an initializer}} +extern A x; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10182,7 +10182,8 @@ assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); // C++11 [dcl.spec.auto]p3 - if (!Init) { + // Except for class argument deduction. + if (!Init && !isa(Deduced)) { assert(VDecl && "no init for init capture deduction?"); Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) << VDecl->getDeclName() << Type; @@ -10202,8 +10203,9 @@ VDecl->getLocation(), DirectInit, Init); // FIXME: Initialization should not be taking a mutable list of inits. SmallVectorInitsCopy(DeduceInits.begin(), DeduceInits.end()); -return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, - InitsCopy); + +return DeduceTemplateSpecializationFromInitializer( + TSI, Entity, Kind, Init ? InitsCopy : MutableArrayRef ()); } if (DirectInit) { Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 = {};
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
Rakete updated this revision to Diff 119035. Rakete added a comment. Rebased and friendly ping :) https://reviews.llvm.org/D38216 Files: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp test/Parser/cxx1z-class-template-argument-deduction.cpp Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 = {}; @@ -13,6 +12,6 @@ A f(0), g{}; // expected-error {{template arguments deduced as 'A' in declaration of 'f' and deduced as 'A' in declaration of 'g'}} struct B { - static A a; // expected-error {{requires an initializer}} + static A a; }; -extern A x; // expected-error {{requires an initializer}} +extern A x; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10174,7 +10174,8 @@ assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); // C++11 [dcl.spec.auto]p3 - if (!Init) { + // Except for class argument deduction. + if (!Init && !isa(Deduced)) { assert(VDecl && "no init for init capture deduction?"); Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) << VDecl->getDeclName() << Type; @@ -10193,7 +10194,10 @@ InitializationKind Kind = InitializationKind::CreateForInit( VDecl->getLocation(), DirectInit, Init); // FIXME: Initialization should not be taking a mutable list of inits. -SmallVectorInitsCopy(DeduceInits.begin(), DeduceInits.end()); +SmallVector InitsCopy; +if (Init) + InitsCopy = {DeduceInits.begin(), DeduceInits.end()}; + return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, InitsCopy); } Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 =
[PATCH] D38216: [C++17] Fix class template argument deduction for default constructors without an initializer
Rakete created this revision. Rakete added a project: clang. As the title says, this makes following code compile: template struct Foo {}; Foo() -> Foo; Foo f; // ok https://reviews.llvm.org/D38216 Files: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp test/Parser/cxx1z-class-template-argument-deduction.cpp Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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 = {}; @@ -13,6 +12,6 @@ A f(0), g{}; // expected-error {{template arguments deduced as 'A' in declaration of 'f' and deduced as 'A' in declaration of 'g'}} struct B { - static A a; // expected-error {{requires an initializer}} + static A a; }; -extern A x; // expected-error {{requires an initializer}} +extern A x; Index: lib/Sema/SemaDecl.cpp === --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10091,7 +10091,8 @@ assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); // C++11 [dcl.spec.auto]p3 - if (!Init) { + // Except for class argument deduction. + if (!Init && !isa(Deduced)) { assert(VDecl && "no init for init capture deduction?"); Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) << VDecl->getDeclName() << Type; @@ -10110,7 +10111,10 @@ InitializationKind Kind = InitializationKind::CreateForInit( VDecl->getLocation(), DirectInit, Init); // FIXME: Initialization should not be taking a mutable list of inits. -SmallVectorInitsCopy(DeduceInits.begin(), DeduceInits.end()); +SmallVector InitsCopy; +if (Init) + InitsCopy = {DeduceInits.begin(), DeduceInits.end()}; + return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, InitsCopy); } Index: test/Parser/cxx1z-class-template-argument-deduction.cpp === --- test/Parser/cxx1z-class-template-argument-deduction.cpp +++ test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -52,7 +52,7 @@ operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} - static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}} + static A x; static constexpr A y = 0; }; @@ -114,7 +114,6 @@ (void)A{n}; (void)new A(n); (void)new A{n}; -// FIXME: We should diagnose the lack of an initializer here. (void)new A; } } @@ -127,7 +126,7 @@ 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}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp === --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.class.deduct/p1.cpp @@ -5,8 +5,7 @@ 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