26

This program, when compiled with VC12 (in Visual Studio 2013 RTM)[1] leads to a crash (in all build configurations), when really it shouldn't:

#include <string>

void foo(std::string const& oops = {})
{
}

int main()
{
    foo();
}

I know of two silent bad codegen bugs that might be related:

Honestly I think these are different, though. Does anyone know

  1. whether there is an actively tracked bug on connect for this
  2. whether there is a workaround (or an explicit description of the situation that causes this bug, so we can look for it/avoid it in our code base)?

[1] Just create an empty project using the C++ Console Application 'wizard'. For simplicity, disable precompiled headers and leave all defaults: https://i.stack.imgur.com/rrrnV.png

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 2
    `return 0;` is missing but seems not to be related... – Mario Jan 10 '14 at 12:38
  • 16
    @Mario, not requred. Also not related. – sehe Jan 10 '14 at 12:39
  • 2
    @Sehe what about https://connect.microsoft.com/VisualStudio/feedback/details/809243/c-11-initializer-lists-as-default-argument? I don't know if it's relevant or related. –  Jan 10 '14 at 12:56
  • @remyabel Thanks! That's exactly what I was looking for. If you mind posting as an answer (I could add a number of workarounds in case you want), we can have this as the answer. – sehe Jan 10 '14 at 13:00
  • 2
    Looks like this is a problem in the general case [vc++](http://rextester.com/CLLDLT38952) Vs [clang and gcc](http://coliru.stacked-crooked.com/a/c8b73cc04ce95cf0). – Shafik Yaghmour Jan 10 '14 at 13:27
  • @ShafikYaghmour Thanks, I wasn't aware of any online compiler capable of vc++, let alone `C++ (vc++) and C - Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86`. Not bad – sehe Jan 10 '14 at 13:31
  • @sehe I try to keep [this](http://stackoverflow.com/a/14652386/1708801) entry up to date when I find new resources, have not in a while. If you know of anything I am missing let me know. Rextester also allows for live cooperation which is neat. – Shafik Yaghmour Jan 10 '14 at 13:44
  • @remyabel what version of `gcc` can you reproduce that on? I can't seem to reproduce on `4.8.1`, maybe a live example would help. What I was referring to though was that `VC++` is calling the wrong constructor in the default argument case, which is weird. – Shafik Yaghmour Jan 10 '14 at 14:13
  • @Shafik Oh I see, disregard my comment then. I mistook your comment to mean the bug exists in both vc++ and gcc/clang. I was conflating `gcc`'s ICE/destructor issues with vc++ calling the wrong constructor. But apparently it's an orthogonal issue. –  Jan 10 '14 at 14:19

2 Answers2

11

It looks like Visual Studio is just broken with respect to which constructor it calls when the default argument is an initializer list. This code:

#include <iostream>

struct test {
  test ()  { std::cout << "test ()" << std::endl ; } 
  test (int)  { std::cout << "test (int)" << std::endl ; }
};

void func( test const &s = {} )
{
}

int main()
{
    test s = {} ;
    func() ;
}

produces this result in gcc and clang, see it live here:

test ()
test ()

while Visual Studio produces this result:

test ()
test (int)

and for this code:

#include <iostream>
#include <initializer_list>

struct test {
  test ()  { std::cout << "test ()" << std::endl ; };

  test (int)  { std::cout << "test (int)" << std::endl ; };
  test ( std::initializer_list<int>) { std::cout << "test (initializer_list<int>)" << std::endl ; } ;
};

void func( test const &s = {0} )
{
}

int main()
{
    test s = {0} ;
    func() ;
}

gcc and clang produce this result see it live here:

 test (initializer_list<int>)
 test (initializer_list<int>)

while Visual Studio produces this error:

 error C2440: 'default argument' : cannot convert from 'initializer-list' to 'const test &'
    Reason: cannot convert from 'initializer-list' to 'const test'
    No constructor could take the source type, or constructor overload resolution was ambiguous

Update

For a sanity check, I went back to the standard to make sure there wasn't some odd rule at the root of this difference or perhaps some restriction that makes this code ill-formed. As far as I can tell this code is not ill-formed. Section 8.3.5 grammar specifically allows this:

parameter-declaration:
  attribute-specifier-seqopt decl-specifier-seq declarator
  attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
  [...]

It does not seem like section 8.5 Initializers or 8.3.6 Default arguments add any restrictions but this defect report 994. braced-init-list as a default argument and working paper Wording for brace-initializers as default arguments make it clear that it was intended and outline the changes made to the standard to allow it and looking at the deltas there are no obvious restrictions.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • I'd comment this over at https://connect.microsoft.com/VisualStudio/feedback/details/809243/c-11-initializer-lists-as-default-argument too, just in case they need any help :/ (Well, perhaps they need help realizing this bug is disruptive) – sehe Jan 10 '14 at 16:22
  • 1
    @sehe comment added to the bug report – Shafik Yaghmour Jan 11 '14 at 03:46
8

An active issue was posted back in November. The sample code posted was:

Compile and run following code in VS2013

#include <string>

void f(std::string s = {}) {
}

int main(int argc, char* argv[]) {
    f();
    return 0;
}

The bug has been acknowledged by Microsoft.

There doesn't seem to be a work-around posted there. Edit Workarounds can easily be based on avoiding the list-initializer syntax:

void f(std::string s = "");
void f(std::string s = std::string());
void f(std::string s = std::string {});

Or just the old-fashioned (if you don't mind introducing overloads):

void f(std::string s);
void f() { f(std::string()); }
sehe
  • 374,641
  • 47
  • 450
  • 633
  • I've added the obvious workarounds. This somewhat answers the question what to look for. I guess grepping for `={}` or `{{}`, `,{}` goes some way to finding occurrences of this. I'm not completely reassured that this will find (all) relevant call sites though. – sehe Jan 10 '14 at 13:09