Guaranteed copy elision and GNU ?: operator

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Guaranteed copy elision and GNU ?: operator

Eric Fiselier via cfe-dev
Hello,

I recently came across an issue when using the gnu conditional
operator (?:) in C++17. In C++14, the code below when compiled with
Clang 5 outputs 42 as expected, but in C++17 the output is 0. In
C++17, I believe the copy constructor for shared_ptr is being elided
and so the ref count is not incremented and the underlying ptr gets
deleted. If the first operand is cast to an rvalue (e.g.,
std::move(makeSharedIntWrapper(42,true)), the behavior is as expected
(since we are disabling the copy elision). Since this is an GNU
extension, is it OK to not elide the copy in this case?

I didn't test to see what gcc does since I don't have ready access to gcc7.

#include <memory>
#include <iostream>

struct int_wrapper {
    int_wrapper(const int& x) : x(new int(x)) {}
    ~int_wrapper() { delete x; }
    int *x;
};

static std::shared_ptr<int_wrapper> makeSharedIntWrapper(int x, bool t) {
    return t ? std::make_shared<int_wrapper>(x) :
std::shared_ptr<int_wrapper>();
}

int main(int argc, const char * argv[]) {
    auto s = makeSharedIntWrapper(42, true) ?:
std::make_shared<int_wrapper>(17);
    std::cout << *s.get()->x << std::endl;

    return 0;
}
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Guaranteed copy elision and GNU ?: operator

Eric Fiselier via cfe-dev
On Tue, Oct 17, 2017 at 3:46 PM, Ronald Wampler <[hidden email]> wrote:

> Hello,
>
> I recently came across an issue when using the gnu conditional
> operator (?:) in C++17. In C++14, the code below when compiled with
> Clang 5 outputs 42 as expected, but in C++17 the output is 0. In
> C++17, I believe the copy constructor for shared_ptr is being elided
> and so the ref count is not incremented and the underlying ptr gets
> deleted. If the first operand is cast to an rvalue (e.g.,
> std::move(makeSharedIntWrapper(42,true)), the behavior is as expected
> (since we are disabling the copy elision). Since this is an GNU
> extension, is it OK to not elide the copy in this case?
>
> I didn't test to see what gcc does since I don't have ready access to gcc7.

I was able to confirm that gcc7 has the same behavior as above.

>
> #include <memory>
> #include <iostream>
>
> struct int_wrapper {
>     int_wrapper(const int& x) : x(new int(x)) {}
>     ~int_wrapper() { delete x; }
>     int *x;
> };
>
> static std::shared_ptr<int_wrapper> makeSharedIntWrapper(int x, bool t) {
>     return t ? std::make_shared<int_wrapper>(x) :
> std::shared_ptr<int_wrapper>();
> }
>
> int main(int argc, const char * argv[]) {
>     auto s = makeSharedIntWrapper(42, true) ?:
> std::make_shared<int_wrapper>(17);
>     std::cout << *s.get()->x << std::endl;
>
>     return 0;
> }
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Guaranteed copy elision and GNU ?: operator

Eric Fiselier via cfe-dev
[+Richard]


On 10/19/2017 08:34 PM, Ronald Wampler via cfe-dev wrote:

> On Tue, Oct 17, 2017 at 3:46 PM, Ronald Wampler <[hidden email]> wrote:
>> Hello,
>>
>> I recently came across an issue when using the gnu conditional
>> operator (?:) in C++17. In C++14, the code below when compiled with
>> Clang 5 outputs 42 as expected, but in C++17 the output is 0. In
>> C++17, I believe the copy constructor for shared_ptr is being elided
>> and so the ref count is not incremented and the underlying ptr gets
>> deleted. If the first operand is cast to an rvalue (e.g.,
>> std::move(makeSharedIntWrapper(42,true)), the behavior is as expected
>> (since we are disabling the copy elision). Since this is an GNU
>> extension, is it OK to not elide the copy in this case?
>>
>> I didn't test to see what gcc does since I don't have ready access to gcc7.
> I was able to confirm that gcc7 has the same behavior as above.

You mean that it prints 0 or 42?

  -Hal

>
>> #include <memory>
>> #include <iostream>
>>
>> struct int_wrapper {
>>      int_wrapper(const int& x) : x(new int(x)) {}
>>      ~int_wrapper() { delete x; }
>>      int *x;
>> };
>>
>> static std::shared_ptr<int_wrapper> makeSharedIntWrapper(int x, bool t) {
>>      return t ? std::make_shared<int_wrapper>(x) :
>> std::shared_ptr<int_wrapper>();
>> }
>>
>> int main(int argc, const char * argv[]) {
>>      auto s = makeSharedIntWrapper(42, true) ?:
>> std::make_shared<int_wrapper>(17);
>>      std::cout << *s.get()->x << std::endl;
>>
>>      return 0;
>> }
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

--
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Guaranteed copy elision and GNU ?: operator

Eric Fiselier via cfe-dev
On Wed, Oct 25, 2017 at 2:09 PM, Hal Finkel <[hidden email]> wrote:

> [+Richard]
>
>
> On 10/19/2017 08:34 PM, Ronald Wampler via cfe-dev wrote:
>>
>> On Tue, Oct 17, 2017 at 3:46 PM, Ronald Wampler <[hidden email]>
>> wrote:
>>>
>>> Hello,
>>>
>>> I recently came across an issue when using the gnu conditional
>>> operator (?:) in C++17. In C++14, the code below when compiled with
>>> Clang 5 outputs 42 as expected, but in C++17 the output is 0. In
>>> C++17, I believe the copy constructor for shared_ptr is being elided
>>> and so the ref count is not incremented and the underlying ptr gets
>>> deleted. If the first operand is cast to an rvalue (e.g.,
>>> std::move(makeSharedIntWrapper(42,true)), the behavior is as expected
>>> (since we are disabling the copy elision). Since this is an GNU
>>> extension, is it OK to not elide the copy in this case?
>>>
>>> I didn't test to see what gcc does since I don't have ready access to
>>> gcc7.
>>
>> I was able to confirm that gcc7 has the same behavior as above.
>
>
> You mean that it prints 0 or 42?

It prints 42 when compiled with c++14 and 0 with c++17 (c++1z).

I also submitted this with a simpler case as
https://bugs.llvm.org/show_bug.cgi?id=35039

Ron

>
>  -Hal
>
>>
>>> #include <memory>
>>> #include <iostream>
>>>
>>> struct int_wrapper {
>>>      int_wrapper(const int& x) : x(new int(x)) {}
>>>      ~int_wrapper() { delete x; }
>>>      int *x;
>>> };
>>>
>>> static std::shared_ptr<int_wrapper> makeSharedIntWrapper(int x, bool t) {
>>>      return t ? std::make_shared<int_wrapper>(x) :
>>> std::shared_ptr<int_wrapper>();
>>> }
>>>
>>> int main(int argc, const char * argv[]) {
>>>      auto s = makeSharedIntWrapper(42, true) ?:
>>> std::make_shared<int_wrapper>(17);
>>>      std::cout << *s.get()->x << std::endl;
>>>
>>>      return 0;
>>> }
>>
>> _______________________________________________
>> cfe-dev mailing list
>> [hidden email]
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
>
> --
> Hal Finkel
> Lead, Compiler Technology and Programming Languages
> Leadership Computing Facility
> Argonne National Laboratory
>
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Guaranteed copy elision and GNU ?: operator

Eric Fiselier via cfe-dev

On 10/25/2017 02:54 PM, Ronald Wampler wrote:

> On Wed, Oct 25, 2017 at 2:09 PM, Hal Finkel <[hidden email]> wrote:
>> [+Richard]
>>
>>
>> On 10/19/2017 08:34 PM, Ronald Wampler via cfe-dev wrote:
>>> On Tue, Oct 17, 2017 at 3:46 PM, Ronald Wampler <[hidden email]>
>>> wrote:
>>>> Hello,
>>>>
>>>> I recently came across an issue when using the gnu conditional
>>>> operator (?:) in C++17. In C++14, the code below when compiled with
>>>> Clang 5 outputs 42 as expected, but in C++17 the output is 0. In
>>>> C++17, I believe the copy constructor for shared_ptr is being elided
>>>> and so the ref count is not incremented and the underlying ptr gets
>>>> deleted. If the first operand is cast to an rvalue (e.g.,
>>>> std::move(makeSharedIntWrapper(42,true)), the behavior is as expected
>>>> (since we are disabling the copy elision). Since this is an GNU
>>>> extension, is it OK to not elide the copy in this case?
>>>>
>>>> I didn't test to see what gcc does since I don't have ready access to
>>>> gcc7.
>>> I was able to confirm that gcc7 has the same behavior as above.
>>
>> You mean that it prints 0 or 42?
> It prints 42 when compiled with c++14 and 0 with c++17 (c++1z).
>
> I also submitted this with a simpler case as
> https://bugs.llvm.org/show_bug.cgi?id=35039

To ask the obvious question, given that this is a GNU extension, has
this been raised with the GCC developers? I imagine that we do want to
match GCC's behavior in this regard.

  -Hal

>
> Ron
>>   -Hal
>>
>>>> #include <memory>
>>>> #include <iostream>
>>>>
>>>> struct int_wrapper {
>>>>       int_wrapper(const int& x) : x(new int(x)) {}
>>>>       ~int_wrapper() { delete x; }
>>>>       int *x;
>>>> };
>>>>
>>>> static std::shared_ptr<int_wrapper> makeSharedIntWrapper(int x, bool t) {
>>>>       return t ? std::make_shared<int_wrapper>(x) :
>>>> std::shared_ptr<int_wrapper>();
>>>> }
>>>>
>>>> int main(int argc, const char * argv[]) {
>>>>       auto s = makeSharedIntWrapper(42, true) ?:
>>>> std::make_shared<int_wrapper>(17);
>>>>       std::cout << *s.get()->x << std::endl;
>>>>
>>>>       return 0;
>>>> }
>>> _______________________________________________
>>> cfe-dev mailing list
>>> [hidden email]
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>> --
>> Hal Finkel
>> Lead, Compiler Technology and Programming Languages
>> Leadership Computing Facility
>> Argonne National Laboratory
>>

--
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Guaranteed copy elision and GNU ?: operator

Eric Fiselier via cfe-dev
On Wed, Oct 25, 2017 at 7:35 PM, Hal Finkel <[hidden email]> wrote:

>
> On 10/25/2017 02:54 PM, Ronald Wampler wrote:
>>
>> On Wed, Oct 25, 2017 at 2:09 PM, Hal Finkel <[hidden email]> wrote:
>>
>> It prints 42 when compiled with c++14 and 0 with c++17 (c++1z).
>>
>> I also submitted this with a simpler case as
>> https://bugs.llvm.org/show_bug.cgi?id=35039
>
>
> To ask the obvious question, given that this is a GNU extension, has this
> been raised with the GCC developers? I imagine that we do want to match
> GCC's behavior in this regard.
>

Argh! This is embarrassing. I'm on a Mac and when I installed gcc I forgot
that `g++` is sym-linked to clang.

It appears that gcc never allowed this code to compile to begin with. See
godbolt: https://godbolt.org/g/8DdytF

So I guess clang should give an error here too.


>  -Hal
>
>
>
> --
> Hal Finkel
> Lead, Compiler Technology and Programming Languages
> Leadership Computing Facility
> Argonne National Laboratory
>
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Guaranteed copy elision and GNU ?: operator

Eric Fiselier via cfe-dev

On 10/25/2017 07:42 PM, Ronald Wampler wrote:

> On Wed, Oct 25, 2017 at 7:35 PM, Hal Finkel <[hidden email]> wrote:
>> On 10/25/2017 02:54 PM, Ronald Wampler wrote:
>>> On Wed, Oct 25, 2017 at 2:09 PM, Hal Finkel <[hidden email]> wrote:
>>>
>>> It prints 42 when compiled with c++14 and 0 with c++17 (c++1z).
>>>
>>> I also submitted this with a simpler case as
>>> https://bugs.llvm.org/show_bug.cgi?id=35039
>>
>> To ask the obvious question, given that this is a GNU extension, has this
>> been raised with the GCC developers? I imagine that we do want to match
>> GCC's behavior in this regard.
>>
> Argh! This is embarrassing. I'm on a Mac and when I installed gcc I forgot
> that `g++` is sym-linked to clang.
>
> It appears that gcc never allowed this code to compile to begin with. See
> godbolt: https://godbolt.org/g/8DdytF
>
> So I guess clang should give an error here too.

Ah, okay. Please update your bug report as well.

  -Hal

>
>
>>   -Hal
>>
>>
>>
>> --
>> Hal Finkel
>> Lead, Compiler Technology and Programming Languages
>> Leadership Computing Facility
>> Argonne National Laboratory
>>

--
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Guaranteed copy elision and GNU ?: operator

Eric Fiselier via cfe-dev
On Oct 25, 2017, at 8:47 PM, Hal Finkel via cfe-dev <[hidden email]> wrote:
On 10/25/2017 07:42 PM, Ronald Wampler wrote:
On Wed, Oct 25, 2017 at 7:35 PM, Hal Finkel <[hidden email]> wrote:
On 10/25/2017 02:54 PM, Ronald Wampler wrote:
On Wed, Oct 25, 2017 at 2:09 PM, Hal Finkel <[hidden email]> wrote:

It prints 42 when compiled with c++14 and 0 with c++17 (c++1z).

I also submitted this with a simpler case as
https://bugs.llvm.org/show_bug.cgi?id=35039

To ask the obvious question, given that this is a GNU extension, has this
been raised with the GCC developers? I imagine that we do want to match
GCC's behavior in this regard.

Argh! This is embarrassing. I'm on a Mac and when I installed gcc I forgot
that `g++` is sym-linked to clang.

It appears that gcc never allowed this code to compile to begin with. See
godbolt: https://godbolt.org/g/8DdytF

So I guess clang should give an error here too.

Ah, okay. Please update your bug report as well.

There are several GCC extensions that we intentionally support in C++ mode even when GCC does not, and IIRC ?: is one of them.

We cannot perform any sort of copy/move elision on the result of ?: because of the rules around the order of destruction of temporaries.  We can of course at least attempt to move it.  It is likely that there is some piece of code which fails to understand this correctly in C++17 mode.

John.


-Hal



 -Hal



--
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory


-- 
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev