Bug 58753 - Brace-initializing a vector with a direct-initialization NSDMI doesn't work in a template
Summary: Brace-initializing a vector with a direct-initialization NSDMI doesn't work i...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: 4.9.1
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks: NSDMI
  Show dependency treegraph
 
Reported: 2013-10-16 18:39 UTC by Ville Voutilainen
Modified: 2014-11-19 09:19 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-10-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ville Voutilainen 2013-10-16 18:39:28 UTC
This snippet doesn't work:

#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;

template <class zomg> 
class T {
        vector<int> v{2,6,4,1,7,1}; // #1, fails
	static int comp(int x, int y) 
	{return x < y;} 
public: 
	void sort_me() {sort(v.begin(), v.end(), comp);} 
	void print_me() {for (auto x : v) cout << x << endl;}
}; 


int main()
{
  T<int> t;
	t.sort_me();
	t.print_me();
}

It works if T is not a class template. It also works if the line
marked #1 is written as
        vector<int> v = {2,6,4,1,7,1};
both in a class template and in a normal class. Fails the same
way with 4.7.2, 4.8 and 4.9 trunk.

Full diagnostics:
plaatti.cpp: In constructor ‘constexpr T<int>::T()’:
plaatti.cpp:8:7: error: no matching function for call to ‘std::vector<int>::vector(<brace-enclosed initializer list>)’
 class T {
       ^
plaatti.cpp:8:7: note: candidates are:
In file included from /usr/local/include/c++/4.9.0/vector:64:0,
                 from plaatti.cpp:1:
/usr/local/include/c++/4.9.0/bits/stl_vector.h:386:9: note: template<class _InputIterator, class> std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const allocator_type&)
         vector(_InputIterator __first, _InputIterator __last,
         ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:386:9: note:   template argument deduction/substitution failed:
plaatti.cpp:8:7: note:   cannot convert ‘4’ (type ‘int’) to type ‘const allocator_type& {aka const std::allocator<int>&}’
 class T {
       ^
In file included from /usr/local/include/c++/4.9.0/vector:64:0,
                 from plaatti.cpp:1:
/usr/local/include/c++/4.9.0/bits/stl_vector.h:358:7: note: std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(initializer_list<value_type> __l,
       ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:358:7: note:   candidate expects 2 arguments, 6 provided
In file included from /usr/local/include/c++/4.9.0/vector:64:0,
                 from plaatti.cpp:1:
/usr/local/include/c++/4.9.0/bits/stl_vector.h:334:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>&&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(vector&& __rv, const allocator_type& __m)
       ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:334:7: note:   candidate expects 2 arguments, 6 provided
/usr/local/include/c++/4.9.0/bits/stl_vector.h:325:7: note: std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(const vector& __x, const allocator_type& __a)
       ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:325:7: note:   candidate expects 2 arguments, 6 provided
/usr/local/include/c++/4.9.0/bits/stl_vector.h:321:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>&&) [with _Tp = int; _Alloc = std::allocator<int>]
       vector(vector&& __x) noexcept
       ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:321:7: note:   candidate expects 1 argument, 6 provided
In file included from /usr/local/include/c++/4.9.0/vector:64:0,
                 from plaatti.cpp:1:
/usr/local/include/c++/4.9.0/bits/stl_vector.h:304:7: note: std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = int; _Alloc = std::allocator<int>]
       vector(const vector& __x)
       ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:304:7: note:   candidate expects 1 argument, 6 provided
In file included from /usr/local/include/c++/4.9.0/vector:64:0,
                 from plaatti.cpp:1:
/usr/local/include/c++/4.9.0/bits/stl_vector.h:275:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(size_type __n, const value_type& __value,
       ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:275:7: note:   candidate expects 3 arguments, 6 provided
In file included from /usr/local/include/c++/4.9.0/vector:64:0,
                 from plaatti.cpp:1:
/usr/local/include/c++/4.9.0/bits/stl_vector.h:263:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(size_type __n, const allocator_type& __a = allocator_type())
       ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:263:7: note:   candidate expects 2 arguments, 6 provided
In file included from /usr/local/include/c++/4.9.0/vector:64:0,
                 from plaatti.cpp:1:
/usr/local/include/c++/4.9.0/bits/stl_vector.h:250:7: note: std::vector<_Tp, _Alloc>::vector(const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(const allocator_type& __a = allocator_type()) _GLIBCXX_NOEXCEPT
       ^
/usr/local/include/c++/4.9.0/bits/stl_vector.h:250:7: note:   candidate expects 1 argument, 6 provided
plaatti.cpp: In function ‘int main()’:
plaatti.cpp:20:10: note: synthesized method ‘constexpr T<int>::T()’ first required here 
   T<int> t;
          ^
Comment 1 Paolo Carlini 2013-10-16 21:40:29 UTC
We badly need a reduced testcase.
Comment 2 Ville Voutilainen 2013-10-16 22:13:17 UTC
This snippet

#include <vector>

struct X {X(int) {}};

template <class zomg> 
class T {
  std::vector<int> x{0}; 
}; 


int main()
{
  T<int> t;
}

gives the following:

plaatti-reduced.cpp: In constructor ‘constexpr T<int>::T()’:
plaatti-reduced.cpp:6:7: error: converting to ‘std::vector<int>’ from initializer list would use explicit constructor ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]’
 class T {
       ^
plaatti-reduced.cpp: In function ‘int main()’:
plaatti-reduced.cpp:13:10: note: synthesized method ‘constexpr T<int>::T()’ first required here 
   T<int> t;
          ^

A non-template is still fine, and a copy-initialized brace-NSDMI is still fine.
Comment 3 Ville Voutilainen 2013-10-16 22:14:53 UTC
And, the struct X is not significant, but I tested with just a simple
type that can be brace-initialized, and that didn't trigger the error.
I haven't yet narrowed it down to initializer_list or anything like that,
vector seems to be a surefire way to trigger it.
Comment 4 Paolo Carlini 2013-10-16 22:23:35 UTC
Thanks Ville. I'm thinking something not including the whole <vector>. I bet 20-30 lines are enough.
Comment 5 Ville Voutilainen 2013-10-16 22:26:29 UTC
I will try a couple of tricks to try and get rid of vector. I don't think it's a library bug, perhaps additional constructor overloads can trigger it. But that'll have to wait until tomorrow. :)
Comment 6 Ville Voutilainen 2013-10-16 22:30:11 UTC
Just one thing: I find it confusing that the diagnostics say
"synthesized method ‘constexpr T<int>::T()" (note the constexpr), there's
not a snowball's chance in hell that that constructor is ever constexpr,
since we _do_ have a vector member here.
Comment 7 Paolo Carlini 2013-10-16 22:35:06 UTC
I see. Let's have first something of manageable size ;) Thanks again!
Comment 8 Ville Voutilainen 2013-10-21 22:06:40 UTC
Slightly reduced, I guess...

#include <initializer_list>

template <class T>
struct X {X(std::initializer_list<int>) {}};

template <class zomg> 
class T {
  X<T> x{1}; 
}; 


int main()
{
  T<int> t;
}



This gives

plaatti-reduced2.cpp: In constructor ‘constexpr T<int>::T()’:
plaatti-reduced2.cpp:7:7: error: no matching function for call to ‘X<T<int> >::X(<brace-enclosed initializer list>)’
 class T {
       ^
plaatti-reduced2.cpp:7:7: note: candidates are:
plaatti-reduced2.cpp:4:11: note: X<T>::X(std::initializer_list<int>) [with T = T<int>]
 struct X {X(std::initializer_list<int>) {}};
           ^
plaatti-reduced2.cpp:4:8: note: constexpr X<T<int> >::X(const X<T<int> >&)
 struct X {X(std::initializer_list<int>) {}};
        ^
plaatti-reduced2.cpp:4:8: note:   no known conversion for argument 1 from ‘int’ to ‘const X<T<int> >&’
plaatti-reduced2.cpp:4:8: note: constexpr X<T<int> >::X(X<T<int> >&&)
plaatti-reduced2.cpp:4:8: note:   no known conversion for argument 1 from ‘int’ to ‘X<T<int> >&&’
plaatti-reduced2.cpp: In function ‘int main()’:
plaatti-reduced2.cpp:14:10: note: synthesized method ‘constexpr T<int>::T()’ first required here 
   T<int> t;
          ^
Comment 9 Paolo Carlini 2013-10-21 22:33:41 UTC
Thanks!
Comment 10 Paolo Carlini 2014-05-15 09:02:21 UTC
Ville, I believe PR58930 is essentially the same issue with a slightly smaller testcase. What do you think?
Comment 11 Ville Voutilainen 2014-05-15 11:38:09 UTC
(In reply to Paolo Carlini from comment #10)

Looks somewhat similar, but not identical. In this particular
bug it doesn't seem to be a case of explicitness being the problem.
Comment 12 Paolo Carlini 2014-05-15 12:19:29 UTC
It is in Comment #2, though. In fact, I *only* noticed that one when I asked ;) Anyway, I was looking a bit into the other bug and interestingly a rather rough draft I have got appears to fix all these issues at once without causing regressions:

Index: init.c
===================================================================
--- init.c      (revision 210459)
+++ init.c      (working copy)
@@ -644,7 +644,8 @@
                    || (TREE_CODE (init) == TREE_LIST
                        && DIRECT_LIST_INIT_P (TREE_VALUE (init))))
                   && (CP_AGGREGATE_TYPE_P (type)
-                      || is_std_init_list (type)))))
+                      || is_std_init_list (type)))
+              || DIRECT_LIST_INIT_P (init)))
     {
       /* With references and list-initialization, we need to deal with
         extending temporary lifetimes.  12.2p5: "A temporary bound to a
Comment 13 Ville Voutilainen 2014-05-15 12:31:10 UTC
(In reply to Paolo Carlini from comment #12)

Ah, indeed, comment 2 has an explicit diagnostic as well. The patch
looks reasonable (to my taste the condition doesn't, but that's another
matter), so I recommend sending it to the mighty maintainer for review.
Comment 14 paolo@gcc.gnu.org 2014-05-20 19:21:31 UTC
Author: paolo
Date: Tue May 20 19:20:59 2014
New Revision: 210653

URL: http://gcc.gnu.org/viewcvs?rev=210653&root=gcc&view=rev
Log:
/cp
2014-05-20  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/58753
	PR c++/58930
	PR c++/58704
	* typeck2.c (digest_nsdmi_init): New.
	* parser.c (cp_parser_late_parse_one_default_arg): Use it.
	* init.c (get_nsdmi): Likewise.
	* cp-tree.h (digest_nsdmi_init): Declare.

/testsuite
2014-05-20  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/58753
	PR c++/58930
	PR c++/58704
	* g++.dg/cpp0x/nsdmi-template11.C: New.
	* g++.dg/cpp0x/nsdmi-template12.C: Likewise.
	* g++.dg/cpp0x/nsdmi-template13.C: Likewise.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/nsdmi-template11.C
    trunk/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C
    trunk/gcc/testsuite/g++.dg/cpp0x/nsdmi-template13.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/cp-tree.h
    trunk/gcc/cp/init.c
    trunk/gcc/cp/parser.c
    trunk/gcc/cp/typeck2.c
    trunk/gcc/testsuite/ChangeLog
Comment 15 Paolo Carlini 2014-05-20 19:22:45 UTC
Fixed for 4.10.0.
Comment 16 ppluzhnikov 2014-07-01 18:46:58 UTC
Author: ppluzhnikov
Date: Tue Jul  1 18:46:26 2014
New Revision: 212207

URL: https://gcc.gnu.org/viewcvs?rev=212207&root=gcc&view=rev
Log:
Backport r210653 from mainline:


gcc/teststuite/ChangeLog:

2014-07-01  Paul Pluzhnikov  <ppluzhnikov@google.com>

	PR c++/58753
	PR c++/58930
	PR c++/58704

	Backported from mainline
	2014-05-20  Paolo Carlini  <paolo.carlini@oracle.com>

	* g++.dg/cpp0x/nsdmi-template11.C: New.
	* g++.dg/cpp0x/nsdmi-template12.C: Likewise.
	* g++.dg/cpp0x/nsdmi-template13.C: Likewise.

gcc/cp/ChangeLog:

2014-07-01  Paul Pluzhnikov  <ppluzhnikov@google.com>

	PR c++/58753
	PR c++/58930
	PR c++/58704

	Backported from mainline
	2014-05-20  Paolo Carlini  <paolo.carlini@oracle.com>

	* typeck2.c (digest_nsdmi_init): New.
	* parser.c (cp_parser_late_parse_one_default_arg): Use it.
	* init.c (get_nsdmi): Likewise.
	* cp-tree.h (digest_nsdmi_init): Declare.


Added:
    branches/gcc-4_9-branch/gcc/testsuite/g++.dg/cpp0x/nsdmi-template11.C
    branches/gcc-4_9-branch/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C
    branches/gcc-4_9-branch/gcc/testsuite/g++.dg/cpp0x/nsdmi-template13.C
Modified:
    branches/gcc-4_9-branch/gcc/cp/ChangeLog
    branches/gcc-4_9-branch/gcc/cp/cp-tree.h
    branches/gcc-4_9-branch/gcc/cp/init.c
    branches/gcc-4_9-branch/gcc/cp/parser.c
    branches/gcc-4_9-branch/gcc/cp/typeck2.c
    branches/gcc-4_9-branch/gcc/testsuite/ChangeLog
Comment 17 christophe.lyon 2014-07-02 07:51:56 UTC
In the 4.9 branch, these new tests fails to compile (ARM & AArch64 targets).
I can see these error messages:

/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template11.C:19:8: error: redefinition of 'struct SampleModule'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template11.C:4:8: error: previous definition of 'struct SampleModule'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template11.C:25:8: error: redefinition of 'struct BaseHandler< <template-parameter-1-1> >'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template11.C:10:8: error: previous definition of 'struct BaseHandler< <template-parameter-1-1> >'

/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C:24:8: error: redefinition of 'struct X<T>'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C:7:8: error: previous definition of 'struct X<T>'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C:27:7: error: redefinition of 'class T<zomg>'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C:10:7: error: previous definition of 'class T<zomg>'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C: In function 'int main()':
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C:31:5: error: redefinition of 'int main()'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template12.C:14:5: note: 'int main()' previously defined here


/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template13.C:15:8: error: redefinition of 'struct A'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template13.C:4:8: error: previous definition of 'struct A'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template13.C:17:27: error: redefinition of 'struct B< <template-parameter-1-1> >'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template13.C:6:27: error: previous definition of 'struct B< <template-parameter-1-1> >'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template13.C:22:8: error: redefinition of 'B<int> b'
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/g++.dg/cpp0x/nsdmi-template13.C:11:8: note: 'B<int> b' previously defined here
Comment 18 christophe.lyon 2014-07-02 08:07:19 UTC
Actually fixed by followup commit 212208. Sorry for the noise.