Bug 53488 - Incorrect code generated when capturing a constant by reference in a lambda
Summary: Incorrect code generated when capturing a constant by reference in a lambda
Status: RESOLVED DUPLICATE of bug 52026
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2012-05-25 16:04 UTC by Jiří Paleček
Modified: 2012-08-19 14:11 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-05-25 00:00:00


Attachments
Preprocessed source (74.04 KB, application/octet-stream)
2012-05-25 16:04 UTC, Jiří Paleček
Details
small test case (164 bytes, text/x-c++src)
2012-06-24 14:21 UTC, Daniel Lunow
Details
integral constant-expression not an integral constant-expression (134 bytes, text/x-c++src)
2012-06-24 14:30 UTC, Daniel Lunow
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jiří Paleček 2012-05-25 16:04:05 UTC
Created attachment 27497 [details]
Preprocessed source

I have the following source:

jirka@debian:~/benchmark$ cat error.cpp 
#include <iostream>

template<class T>
void f()
{
  const int i=sizeof(T);
  auto fun = [&] { std::cout << i << std::endl; };
  fun();
}

int main()
{
  f<double>();
  return 0;
}

When I compile and run this program, it outputs garbage (instead of sizeof(double)):

jirka@debian:~/benchmark$ g++-4.7 --std=c++0x error.cpp
jirka@debian:~/benchmark$ ./a.out 
134514706

Changing f to a nontemplate, i to be nondependent ot captured by value produces correct output.
Comment 1 Jonathan Wakely 2012-05-25 16:16:25 UTC
The bug rpeorting guidelines ask for the output of 'gcc -v' so we at least know which version you're using, "g++-4.7" isn't very useful. I'm assuming 4.7.0
Comment 2 Jiří Paleček 2012-05-25 17:54:00 UTC
The bug occurs with these compiler versions:

jirka@debian:~/benchmark$ g++-4.7 -v
Using built-in specs.
COLLECT_GCC=g++-4.7
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i486-linux-gnu/4.7/lto-wrapper
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.0-9' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.7.0 (Debian 4.7.0-9) 

jirka@debian:~/benchmark$ LD_LIBRARY_PATH=/usr/lib/gcc-snapshot/lib:$LD_LIBRARY_PATH PATH=/usr/lib/gcc-snapshot/bin:$PATH g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc-snapshot/libexec/gcc/i486-linux-gnu/4.8.0/lto-wrapper
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 20120501-1' --with-bugurl=file:///usr/share/doc/gcc-snapshot/README.Bugs --enable-languages=c,ada,c++,java,go,fortran,objc,obj-c++ --prefix=/usr/lib/gcc-snapshot --enable-shared --enable-linker-build-id --with-system-zlib --disable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-snap/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-snap --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-snap --with-arch-directory=i386 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-targets=all --with-arch-32=i586 --with-tune=generic --disable-werror --enable-checking=yes --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.8.0 20120501 (experimental) [trunk revision 187013] (Debian 20120501-1)
Comment 3 Daniel Krügler 2012-05-25 20:09:20 UTC
An interesting aspect of this example is that when using gcc 4.8.0 20120520 (experimental) compiled in C++11 mode with -Wall it produces the warning

"7|warning: 'i' is used uninitialized in this function [-Wuninitialized]"

where line 7 is the line of the lambda-expression and producing an output of:

0
Comment 4 Daniel Lunow 2012-06-24 14:21:31 UTC
Created attachment 27693 [details]
small test case

Just wanted to report the same bug with gcc 4.7.1. 
I found out, that it occurs, if the initializer depends on some template argument.

C:\dev\projects\compiler test>g++ -std=c++11 gcc_test5.cpp -Wall -o gcc_test5.exe
gcc_test5.cpp: In lambda function:
gcc_test5.cpp:10:29: warning: 'i' is used uninitialized in this function [-Wuninitialized]

C:\dev\projects\compiler test>gcc_test5.exe
0
which should have given 4.
Comment 5 Daniel Lunow 2012-06-24 14:30:19 UTC
Created attachment 27694 [details]
integral constant-expression not an integral constant-expression

This test case should compile, but it does not. Its not the same as the constant not beeing captured, but I can imagine it is very close problem.

C:\dev\projects\compiler test>g++ -std=c++11 gcc_test6.cpp
gcc_test6.cpp: In instantiation of 'foo() [with T = void]::<lambda()>':
gcc_test6.cpp:8:4:   required from 'struct foo() [with T = void]::<lambda()>'
gcc_test6.cpp:8:3:   required from 'void foo() [with T = void]'
gcc_test6.cpp:13:13:   required from here
gcc_test6.cpp:8:15: error: size of array is not an integral constant-expression
Comment 6 Jiří Paleček 2012-06-24 20:12:43 UTC
Daniel, sorry, but I don't think your second ex
Comment 7 Jiří Paleček 2012-06-24 20:23:38 UTC
Daniel, sorry, but I don't think your second example is relevant. First this bug occurs only when capturing by reference, not by value, but your second example uses capture by value. Moreover, while reading the standard, I can't find anything that mandates the usage like yours to work. AFAIK it allows the compiler to treat the lambda from your second example akin to this:

int foo() {
  const int i = 1;
  struct Lambda {
    const int i;
    Lambda(int i_) : i(i_) {}
    void operator()()const {
      int x[i];
    }
  };
  Lambda l(i);
}

which wouldn't work, and quite rightly. It couldn't even be modified to work, as i must be static if it has to be both compile time constant and member of a class.
Comment 8 Daniel Lunow 2012-06-25 00:32:00 UTC
Then you must have missed the example in 5.1.2 [expr.prim.lambda] p. 12.
[Example:
void f1(int i) {
  int const N = 20;
  auto m1 = [=]{
    int const M = 30;
    auto m2 = [i]{
      int x[N][M]; // OK: N and M are not odr-used
      // ...
    };
  };
  // ...
}
- end example]
Sure its non-normative, but this is what has always worked through a combination of
8.3.4 [dcl.array], 3.4.1p1,6 [basic.lookup.unqual], 3.3.1p1 [basic.scope.declarative], 3.3.3p1,3 [basic.scope.local] and 5.19p2 [expr.const].

By the way the bug is independent of capturing by value/reference and in my second example nothing is captured at all. It is not necessary to capture, because i is not odr-used (5.1.2p11, 3.2p2).

I just put it here because, it occurs under the same circumstances 
 * constant integral local variable
 * initialized by an expression dependent on a template parameter, but not if the initializer is the name of a non-template type parameter
 * used (but not odr-used) inside lambda.
and of course gcc has no problems with both examples, if i's initialization does not depend on a template parameter.
Comment 9 Ai Azuma 2012-06-25 14:28:00 UTC
I don't know if that helps, but there exists a bug report similar to one reported in Comment 0.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50939
Comment 10 Jiří Paleček 2012-08-19 14:04:34 UTC
I found a similar preceding bugreport 52026. Therefore, I'm marking as duplicate.

*** This bug has been marked as a duplicate of bug 52026 ***
Comment 11 Jiří Paleček 2012-08-19 14:11:22 UTC
BTW I have proposed a patch that fixes this problem here: http://gcc.gnu.org/ml/gcc-patches/2012-08/msg01252.html. Please take a look at it.