[cfe-dev] [bug?] list-initialization failures in a return statement

Richard Smith richard at metafoo.co.uk
Thu Aug 21 18:47:57 PDT 2014


On Thu, Aug 21, 2014 at 5:26 PM, Jim Porter <jvp4846 at g.rit.edu> wrote:

> On 8/21/2014 4:00 PM, Richard Smith wrote:
>
>> On Mon, Aug 18, 2014 at 8:59 AM, Jim Porter <jvp4846 at g.rit.edu
>> <mailto:jvp4846 at g.rit.edu>> wrote:
>>
>>     I've found what I think are a couple of bugs in how clang (3.4)
>>     list-initializes objects in a return statement. It probably applies
>>     to any copy-list-initialization context, but I haven't tested all
>>     the possibilities. I'm posting this here instead of just filing a
>>     bug because I wanted to get some feedback on whether I'm correct
>>     about this or not.
>>
>>     --------------------
>>
>>     First, I think clang is incorrectly failing on the explicit default
>>     constructor in this sample:
>>
>>        struct foo {
>>          explicit foo() {}
>>        };
>>
>>        foo make_foo() {
>>          return {};
>>        }
>>
>>        int main() {
>>          auto f = make_foo();
>>          return 0;
>>        }
>>
>>     clang tells me "chosen constructor is explicit in
>>     copy-initialization", but according to 8.5.4p3, make_foo should be
>>     value-initializing foo:
>>
>>        If the initializer list has no elements and T is a class type with
>> a
>>        default constructor, the object is value-initialized.
>>
>>
>> OK, but value-initialization defers to default-initialization here, and
>> default-initialization performs overload resolution to select the
>> default constructor. This -- presumably -- uses 13.3.1.7 to select the
>> constructor:
>>
>> "When objects of non-aggregate class type T are list-initialized
>> (8.5.4), overload resolution selects the constructor in two phases:
>>   -- [choose from initializer-list constructors]
>>   -- [try all constructors]
>> If the initializer list has no elements and T has a default constructor,
>> the first phase is omitted. In copy-list-initialization, if an explicit
>> constructor is chosen, the initialization is ill-formed."
>>
>> Since we're in copy-list-initialization, T has a default constructor,
>> and the list has no elements, we try all constructors. Since we pick an
>> explicit constructor, the program is ill-formed.
>>
>
> Hmm. Does this mean it's impossible to write a function that constructs an
> arbitrary DefaultConstructible object? I had hoped to do something like
>
>   template<typename T>
>   T make() {
>     return {};
>   }
>
> so that I could construct non-movable objects, but I guess that won't work
> for objects with explicit default constructors. It seems like clang is
> indeed doing the right thing, so perhaps this is an issue to bring up with
> the standards committee...


If you'll excuse me making up terms, DefaultConstructible only requires
that direct-default-initialization is valid, not that
copy-default-list-initialization is valid. That's probably the bug in the
standard; your type should probably not be considered to be
DefaultConstructible.

Here's a dumb workaround:

  template<typename T> struct DirectInit {
    T value{};
    operator T&() & { return value; }
    operator T&&() && { return value; }
    // ...
  };
  template<typename T> DirectInit<T> make() { return {}; }

... but I'm somewhat wondering why you would have an explicit default
constructor in the first place.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140821/8ef16972/attachment.html>


More information about the cfe-dev mailing list