No warning when lambda returns reference to temporary

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

No warning when lambda returns reference to temporary

Alex Denisov via cfe-dev
Hiya,

I ran into this (presumably) undefined behaviour today, and wonder if it's a bug or expected. My app was coded similarly and ran correctly on macOS/LLVM version 8.1.0 (clang-802.0.38) but not Ubuntu14.04/gcc-4.7.3-12ubuntu1

In the case of this code, it's invalid since the lambda returns a reference to a temp object. My bad, I'll fix it. Seems the compiler could've warned me though :)

Compiler warns when explicitly specifying the return type of the lambda using `->` operator, but not when implicit. Is this expected or a bug?

Thanks in advance,
Matt

// Minimal test case:

#include <functional>

#include <iostream>


void print_stuff(std::function<const int&()> f) {

    std::cout << "stuff is: " << f() << std::endl;

}


int main(int argc, char *argv[]) {

    print_stuff([]() {

        int i = 123;

        return i;

    });

}


_______________________________________________
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: No warning when lambda returns reference to temporary

Alex Denisov via cfe-dev
Hi Matthew,

When you don't specify a return type for the lambda, the compiler
deduces 'int', not 'int&'.

auto deduced     = []()         { int i = 123; return i; };
auto spelled_out = []() -> int& { int i = 123; return i; };

int d = deduced;
int s = spelled_out;

This doesn't compile of course, but the error messages are the useful info:

$ g++-8 -std=c++11 is_it_ref.cpp
is_it_ref.cpp: In lambda function:
is_it_ref.cpp:2:39: warning: reference to local variable ‘i’ returned
[-Wreturn-local-addr]
 auto spelled_out = []() -> int& { int i = 123; return i; };
                                       ^
is_it_ref.cpp: At global scope:
is_it_ref.cpp:4:9: error: invalid user-defined conversion from
‘<lambda()>’ to ‘int’ [-fpermissive]
 int d = deduced;
         ^~~~~~~
is_it_ref.cpp:1:23: note: candidate is: ‘<lambda()>::operator int
(*)()() const’ <near match>
 auto deduced     = []()         { int i = 123; return i; };
                       ^
is_it_ref.cpp:1:23: note:   no known conversion from ‘int (*)()’ to ‘int’
is_it_ref.cpp:5:9: error: invalid user-defined conversion from
‘<lambda()>’ to ‘int’ [-fpermissive]
 int s = spelled_out;
         ^~~~~~~~~~~
is_it_ref.cpp:2:31: note: candidate is: ‘<lambda()>::operator int&
(*)()() const’ <near match>
 auto spelled_out = []() -> int& { int i = 123; return i; };
                               ^
is_it_ref.cpp:2:31: note:   no known conversion from ‘int& (*)()’ to ‘int’


On Thu, Jul 13, 2017 at 6:55 AM, Matthew Urquhart via cfe-dev
<[hidden email]> wrote:

> Hiya,
>
> I ran into this (presumably) undefined behaviour today, and wonder if it's a
> bug or expected. My app was coded similarly and ran correctly on macOS/LLVM
> version 8.1.0 (clang-802.0.38) but not Ubuntu14.04/gcc-4.7.3-12ubuntu1
>
> In the case of this code, it's invalid since the lambda returns a reference
> to a temp object. My bad, I'll fix it. Seems the compiler could've warned me
> though :)
>
> Compiler warns when explicitly specifying the return type of the lambda
> using `->` operator, but not when implicit. Is this expected or a bug?
>
> Thanks in advance,
> Matt
>
> // Minimal test case:
>
> #include <functional>
>
> #include <iostream>
>
>
> void print_stuff(std::function<const int&()> f) {
>
>     std::cout << "stuff is: " << f() << std::endl;
>
> }
>
>
> int main(int argc, char *argv[]) {
>
>     print_stuff([]() {
>
>         int i = 123;
>
>         return i;
>
>     });
>
> }
>
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>



--
GCS a+ e++ d- C++ ULS$ L+$ !E- W++ P+++$ w++$ tv+ b++ DI D++ 5++
The Tao of math: The numbers you can count are not the real numbers.
Life is complex, with real and imaginary parts.
"Ok, it boots. Which means it must be bug-free and perfect. " -- Linus Torvalds
"People disagree with me. I just ignore them." -- Linus Torvalds
_______________________________________________
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: No warning when lambda returns reference to temporary

Alex Denisov via cfe-dev
Hi Csaba,

Thanks very much for the reply - makes sense. I was originally having trouble with strings, but switched to ints for a shorter "minimal case."

In this case since the lambda returns an `int`, it's now `std::function<int()>` not `std::function<const int&()>` which on the surface seems it should be a mismatching type.

Minimal case updated for strings below. Strangely, it works correctly on macOS but invokes undefined behaviour on ubuntu.

Cheers,
Matt

#include <functional>

#include <iostream>

#include <sstream>


void print_stuff(std::function<const std::string&()> f) {

    std::cout << "stuff is: " << f() << std::endl;

}


int main(int argc, char *argv[]) {

    print_stuff([&]() {

        std::stringstream ss;

        ss << argc;

        return ss.str();

    });

}


On Thu, Jul 13, 2017 at 5:08 PM Csaba Raduly <[hidden email]> wrote:
Hi Matthew,

When you don't specify a return type for the lambda, the compiler
deduces 'int', not 'int&'.

auto deduced     = []()         { int i = 123; return i; };
auto spelled_out = []() -> int& { int i = 123; return i; };

int d = deduced;
int s = spelled_out;

This doesn't compile of course, but the error messages are the useful info:

$ g++-8 -std=c++11 is_it_ref.cpp
is_it_ref.cpp: In lambda function:
is_it_ref.cpp:2:39: warning: reference to local variable ‘i’ returned
[-Wreturn-local-addr]
 auto spelled_out = []() -> int& { int i = 123; return i; };
                                       ^
is_it_ref.cpp: At global scope:
is_it_ref.cpp:4:9: error: invalid user-defined conversion from
‘<lambda()>’ to ‘int’ [-fpermissive]
 int d = deduced;
         ^~~~~~~
is_it_ref.cpp:1:23: note: candidate is: ‘<lambda()>::operator int
(*)()() const’ <near match>
 auto deduced     = []()         { int i = 123; return i; };
                       ^
is_it_ref.cpp:1:23: note:   no known conversion from ‘int (*)()’ to ‘int’
is_it_ref.cpp:5:9: error: invalid user-defined conversion from
‘<lambda()>’ to ‘int’ [-fpermissive]
 int s = spelled_out;
         ^~~~~~~~~~~
is_it_ref.cpp:2:31: note: candidate is: ‘<lambda()>::operator int&
(*)()() const’ <near match>
 auto spelled_out = []() -> int& { int i = 123; return i; };
                               ^
is_it_ref.cpp:2:31: note:   no known conversion from ‘int& (*)()’ to ‘int’


On Thu, Jul 13, 2017 at 6:55 AM, Matthew Urquhart via cfe-dev
<[hidden email]> wrote:
> Hiya,
>
> I ran into this (presumably) undefined behaviour today, and wonder if it's a
> bug or expected. My app was coded similarly and ran correctly on macOS/LLVM
> version 8.1.0 (clang-802.0.38) but not Ubuntu14.04/gcc-4.7.3-12ubuntu1
>
> In the case of this code, it's invalid since the lambda returns a reference
> to a temp object. My bad, I'll fix it. Seems the compiler could've warned me
> though :)
>
> Compiler warns when explicitly specifying the return type of the lambda
> using `->` operator, but not when implicit. Is this expected or a bug?
>
> Thanks in advance,
> Matt
>
> // Minimal test case:
>
> #include <functional>
>
> #include <iostream>
>
>
> void print_stuff(std::function<const int&()> f) {
>
>     std::cout << "stuff is: " << f() << std::endl;
>
> }
>
>
> int main(int argc, char *argv[]) {
>
>     print_stuff([]() {
>
>         int i = 123;
>
>         return i;
>
>     });
>
> }
>
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>



--
GCS a+ e++ d- C++ ULS$ L+$ !E- W++ P+++$ w++$ tv+ b++ DI D++ 5++
The Tao of math: The numbers you can count are not the real numbers.
Life is complex, with real and imaginary parts.
"Ok, it boots. Which means it must be bug-free and perfect. " -- Linus Torvalds
"People disagree with me. I just ignore them." -- Linus Torvalds

_______________________________________________
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: No warning when lambda returns reference to temporary

Alex Denisov via cfe-dev


On Thu, Jul 13, 2017 at 2:24 AM Matthew Urquhart via cfe-dev <[hidden email]> wrote:
Hi Csaba,

Thanks very much for the reply - makes sense. I was originally having trouble with strings, but switched to ints for a shorter "minimal case."

In this case since the lambda returns an `int`, it's now `std::function<int()>` not `std::function<const int&()>` which on the surface seems it should be a mismatching type.

So this is where the kicker/punchline is - a lambda isn't a std::function, a lambda is just its own type with an op() overload.

std::function wraps any /compatible/ callable.

So basically if you have some callable object 'f' and this is valid:

  T1 g(T2 t2, <and so on>) {
    return f(std::forward<T2>(t2), <and so on>);
  }
 
then 'f' is implicitly convertible to std::function<T1(T2, <and so on>)>

What that means in reality is that, yes, because this is valid (yet buggy):

  int f();
  const int &g() {
    return f();
  }

so is this:

  std::function<const int&()> g = f;

You can get similar kinds of issues with parameters too:

  void f(bool);
  std::function<void(T*)> g = f; //valid but perhaps surprising (f(true) if g(non-null), f(false) if g(null-pointer))


Minimal case updated for strings below. Strangely, it works correctly on macOS but invokes undefined behaviour on ubuntu.

Cheers,
Matt

#include <functional>

#include <iostream>

#include <sstream>


void print_stuff(std::function<const std::string&()> f) {

    std::cout << "stuff is: " << f() << std::endl;

}


int main(int argc, char *argv[]) {

    print_stuff([&]() {

        std::stringstream ss;

        ss << argc;

        return ss.str();

    });

}


On Thu, Jul 13, 2017 at 5:08 PM Csaba Raduly <[hidden email]> wrote:
Hi Matthew,

When you don't specify a return type for the lambda, the compiler
deduces 'int', not 'int&'.

auto deduced     = []()         { int i = 123; return i; };
auto spelled_out = []() -> int& { int i = 123; return i; };

int d = deduced;
int s = spelled_out;

This doesn't compile of course, but the error messages are the useful info:

$ g++-8 -std=c++11 is_it_ref.cpp
is_it_ref.cpp: In lambda function:
is_it_ref.cpp:2:39: warning: reference to local variable ‘i’ returned
[-Wreturn-local-addr]
 auto spelled_out = []() -> int& { int i = 123; return i; };
                                       ^
is_it_ref.cpp: At global scope:
is_it_ref.cpp:4:9: error: invalid user-defined conversion from
‘<lambda()>’ to ‘int’ [-fpermissive]
 int d = deduced;
         ^~~~~~~
is_it_ref.cpp:1:23: note: candidate is: ‘<lambda()>::operator int
(*)()() const’ <near match>
 auto deduced     = []()         { int i = 123; return i; };
                       ^
is_it_ref.cpp:1:23: note:   no known conversion from ‘int (*)()’ to ‘int’
is_it_ref.cpp:5:9: error: invalid user-defined conversion from
‘<lambda()>’ to ‘int’ [-fpermissive]
 int s = spelled_out;
         ^~~~~~~~~~~
is_it_ref.cpp:2:31: note: candidate is: ‘<lambda()>::operator int&
(*)()() const’ <near match>
 auto spelled_out = []() -> int& { int i = 123; return i; };
                               ^
is_it_ref.cpp:2:31: note:   no known conversion from ‘int& (*)()’ to ‘int’


On Thu, Jul 13, 2017 at 6:55 AM, Matthew Urquhart via cfe-dev
<[hidden email]> wrote:
> Hiya,
>
> I ran into this (presumably) undefined behaviour today, and wonder if it's a
> bug or expected. My app was coded similarly and ran correctly on macOS/LLVM
> version 8.1.0 (clang-802.0.38) but not Ubuntu14.04/gcc-4.7.3-12ubuntu1
>
> In the case of this code, it's invalid since the lambda returns a reference
> to a temp object. My bad, I'll fix it. Seems the compiler could've warned me
> though :)
>
> Compiler warns when explicitly specifying the return type of the lambda
> using `->` operator, but not when implicit. Is this expected or a bug?
>
> Thanks in advance,
> Matt
>
> // Minimal test case:
>
> #include <functional>
>
> #include <iostream>
>
>
> void print_stuff(std::function<const int&()> f) {
>
>     std::cout << "stuff is: " << f() << std::endl;
>
> }
>
>
> int main(int argc, char *argv[]) {
>
>     print_stuff([]() {
>
>         int i = 123;
>
>         return i;
>
>     });
>
> }
>
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>



--
GCS a+ e++ d- C++ ULS$ L+$ !E- W++ P+++$ w++$ tv+ b++ DI D++ 5++
The Tao of math: The numbers you can count are not the real numbers.
Life is complex, with real and imaginary parts.
"Ok, it boots. Which means it must be bug-free and perfect. " -- Linus Torvalds
"People disagree with me. I just ignore them." -- Linus Torvalds
_______________________________________________
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