Bug 51253 - [C++11][DR 1030] Evaluation order (sequenced-before relation) among initializer-clauses in braced-init-list
Summary: [C++11][DR 1030] Evaluation order (sequenced-before relation) among initializ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.0
: P2 normal
Target Milestone: 4.9.1
Assignee: Jason Merrill
URL:
Keywords: wrong-code
: 62036 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-11-21 04:08 UTC by Ai Azuma
Modified: 2022-01-20 03:47 UTC (History)
7 users (show)

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


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ai Azuma 2011-11-21 04:08:01 UTC
Since DR 1030 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030 was accepted, I expect that the following code is well-defined and exits with the status code 0. However, GCC 4.7.0 20111112 (experimental) with -std=c++11 produces a wrong executable. In addition, it spuriously warns about undefined operations with -Wsequence-point option.

//////////////////////////////////
struct swallow{
  template<typename... Types>
  swallow(Types &&...){}
};

template<int... IS>
int f()
{
  int i = 2;
  swallow{ i = i * IS + IS... };
  return i;
}

int main()
{
  // `i = i * 2 + 2' should be sequenced before `i = i * 3 + 3'
  return f<2, 3>() == 21 ? 0 : 1;
}
//////////////////////////////////
Comment 1 Paolo Carlini 2012-10-10 09:24:08 UTC
Confirming.
Comment 2 Akim Demaille 2013-07-05 13:49:24 UTC
Ping.  Still there with released 4.8.1 on GNU/Linux.  Using initializer lists this way is a very handy way to handle variadic templates.

Cheers, and thanks for all the good work!
Comment 3 Broes De Cat 2013-08-13 17:06:59 UTC
Confirmed, hit the bug with 4.7.3 in c++11 mode.
Comment 4 Stephan Tolksdorf 2013-10-23 16:38:44 UTC
I just stumbled over this bug with the current trunk version of GCC. It's a pretty ugly bug.
Comment 5 Akim Demaille 2013-11-25 11:54:37 UTC
Happy two-year birthday, bug!  Sorry I'm (slightly more that) off-by-one.
Comment 6 Akim Demaille 2014-01-18 16:12:11 UTC
FWIW, because of this issue, I no longer use g++ for my project, which saddens me.  If there were a means to put money on some bugs, I'd be happy to drop say $50.  I do not pretend that should suffice, but maybe other people would be happy to put money on their bugs, and maybe in end some bugs might be worth shooting at.  Sort of crowd-funding.  Of course it would require some infrastructure to support this, but maybe this would be worth considering?

Best regards.
Comment 7 Akim Demaille 2014-03-06 14:38:49 UTC
Hi all,

I'd really love to have some feedback on this issue.  It looks like nobody is having a look at this.

Thanks for all the good work, and sorry for insisting.
Comment 8 Paolo Carlini 2014-03-13 17:07:48 UTC
Let's add Jason in CC.
Comment 9 Manuel López-Ibáñez 2014-03-13 17:40:29 UTC
(In reply to Akim Demaille from comment #6)
> FWIW, because of this issue, I no longer use g++ for my project, which
> saddens me.  If there were a means to put money on some bugs, I'd be happy
> to drop say $50.  I do not pretend that should suffice, but maybe other
> people would be happy to put money on their bugs, and maybe in end some bugs
> might be worth shooting at.  Sort of crowd-funding.  Of course it would
> require some infrastructure to support this, but maybe this would be worth
> considering?

It would be nice if such infrastructure existed. Perhaps it would motivate more people to contribute to GCC (current contributors have their hands pretty full already). I know of: https://www.bountysource.com/trackers/384568-gcc
but I have never used it, so I don't know how it works.
Comment 10 Akim Demaille 2014-04-10 08:14:32 UTC
Well, I have finally found a simple workaround for some of the cases: GCC seems to be right in the order of evaluation when initializing an array so:

template<int... IS>
int f1()
{
  int i = 0;
  swallow{ i = 10 * i + IS... };
  return i;
}

fails, but

template<int... IS>
int f2()
{
  using swallow = int[];
  int i = 0;
  (void) swallow{ i = 10 * i + IS... };
  return i;
}

succeeds.  However, GCC's own libstdc++ is exposed to this bug, for instance make_tuple.

$ cat foo.cc
#include <iostream>
#include <tuple>

struct swallow
{
  template<typename... Types>
  swallow(Types &&...){}
};

int incr()
{
  static int res = 2;
  return res++;
}

template<int... IS>
int f1()
{
  int i = 0;
  swallow{ i = 10 * i + IS... };
  return i;
}

template<int... IS>
int f2()
{
  using swallow = int[];
  int i = 0;
  (void) swallow{ i = 10 * i + IS... };
  return i;
}

int main()
{
  // `i = i * 2 + 2' should be sequenced before `i = i * 3 + 3'
  std::cerr << f1<2, 3>() << '\t';
  std::cerr << f2<2, 3>() << '\t';
  auto t = std::make_tuple(incr(), incr());
  std::cerr << std::get<0>(t) << std::get<1>(t) << '\n';
}

$ ./a.32
23	23	23
$ ./a.33
23	23	23
$ ./a.34
23	23	23
$ ./a.35
23	23	23
$ ./a.48
32	23	32
$ ./a.49
32	23	32

where 32...35 is clang++, and 48,49 is gcc.
Comment 11 Jason Merrill 2014-04-11 17:09:20 UTC
Author: jason
Date: Fri Apr 11 17:08:47 2014
New Revision: 209309

URL: http://gcc.gnu.org/viewcvs?rev=209309&root=gcc&view=rev
Log:
	DR 1030
	PR c++/51253
	* cp-tree.h (CALL_EXPR_LIST_INIT_P): New.
	* call.c (struct z_candidate): Add flags field.
	(add_candidate): Add flags parm.
	(add_function_candidate, add_conv_candidate, build_builtin_candidate)
	(add_template_candidate_real): Pass it.
	(build_over_call): Set CALL_EXPR_LIST_INIT_P.
	* tree.c (build_aggr_init_expr): Copy it.
	* semantics.c (simplify_aggr_init_expr): Preevaluate args if it's set.

Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
    trunk/gcc/cp/cp-tree.h
    trunk/gcc/cp/semantics.c
    trunk/gcc/cp/tree.c
Comment 12 Jason Merrill 2014-06-03 00:18:35 UTC
Fixed on trunk so far.
Comment 13 Jonathan Wakely 2014-06-03 09:29:35 UTC
(In reply to Akim Demaille from comment #10)
>   auto t = std::make_tuple(incr(), incr());

That's not an initializer-list, it's a function call, so the order of evaluation is not specified and that example is not relevant AFAICT.
Comment 14 Jonathan Wakely 2014-06-04 01:11:22 UTC
Trunk still gives -Wsequence-point warnings, and PR 61382 has an example that still fails
Comment 15 Akim Demaille 2014-06-04 06:22:59 UTC
(In reply to Jonathan Wakely from comment #13)
> (In reply to Akim Demaille from comment #10)
> >   auto t = std::make_tuple(incr(), incr());
> 
> That's not an initializer-list, it's a function call, so the order of
> evaluation is not specified and that example is not relevant AFAICT.

Yes, you are right, I had also realized that afterwards.  It would be
nice though if the standard could ensure that perfect forwarding could
preserve the guarantee on left-to-right "upward": convenience functions,
that wrap constructors for instance, could still be used safely.
Comment 16 Jason Merrill 2014-06-04 15:51:34 UTC
Author: jason
Date: Wed Jun  4 15:51:01 2014
New Revision: 211235

URL: http://gcc.gnu.org/viewcvs?rev=211235&root=gcc&view=rev
Log:
	PR c++/51253
	PR c++/61382
gcc/
	* gimplify.c (gimplify_arg): Non-static.
	* gimplify.h: Declare it.
gcc/cp/
	* cp-gimplify.c (cp_gimplify_expr): Handle CALL_EXPR_LIST_INIT_P here.
	* semantics.c (simplify_aggr_init_expr): Not here, just copy it.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/initlist86.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/cp-gimplify.c
    trunk/gcc/cp/semantics.c
    trunk/gcc/gimplify.c
    trunk/gcc/gimplify.h
Comment 17 Jason Merrill 2014-06-30 14:25:56 UTC
Author: jason
Date: Mon Jun 30 14:25:21 2014
New Revision: 212150

URL: https://gcc.gnu.org/viewcvs?rev=212150&root=gcc&view=rev
Log:
	DR 1030
	PR c++/51253
	PR c++/61382
	* cp-tree.h (CALL_EXPR_LIST_INIT_P): New.
	* call.c (struct z_candidate): Add flags field.
	(add_candidate): Add flags parm.
	(add_function_candidate, add_conv_candidate, build_builtin_candidate)
	(add_template_candidate_real): Pass it.
	(build_over_call): Set CALL_EXPR_LIST_INIT_P.
	* tree.c (build_aggr_init_expr): Copy it.
	* semantics.c (simplify_aggr_init_expr): Copy it.
	* cp-gimplify.c (cp_gimplify_expr): Handle it.

Added:
    branches/gcc-4_9-branch/gcc/testsuite/g++.dg/cpp0x/initlist86.C
Modified:
    branches/gcc-4_9-branch/gcc/ChangeLog
    branches/gcc-4_9-branch/gcc/cp/ChangeLog
    branches/gcc-4_9-branch/gcc/cp/call.c
    branches/gcc-4_9-branch/gcc/cp/cp-gimplify.c
    branches/gcc-4_9-branch/gcc/cp/cp-tree.h
    branches/gcc-4_9-branch/gcc/cp/semantics.c
    branches/gcc-4_9-branch/gcc/cp/tree.c
    branches/gcc-4_9-branch/gcc/gimplify.c
    branches/gcc-4_9-branch/gcc/gimplify.h
Comment 18 christophe.lyon 2014-07-01 08:20:30 UTC
On 4.9 branch, I've noticed that commit 212150 adds new FAILs on some configurations. g++.dg/cpp0x/initlist86.C fails at execution in the following cases (tested with qemu):
target                     mode  cpu
arm-none-eabi              arm   cortex-a9
arm-none-linux-gnueabi     arm   cortex-a9
arm-none-linux-gnueabi     thumb cortex-a9
arm-none-linux-gnueabihf   arm   cortex-a9
arm-none-linux-gnueabihf   thumb cortex-a9
arm-none-linux-gnueabihf   arm   cortex-a9
armeb-none-linux-gnueabihf arm   cortex-a9
armeb-none-linux-gnueabihf thumb cortex-a9
aarch64-none-linux

the same test passes when:
target                     mode  cpu
arm-none-eabi              thumb cortex-a9
aarch64-none-elf
aarch64_be-none-elf
Comment 19 Jason Merrill 2014-07-03 02:09:44 UTC
That's odd.  Can you investigate further?
Comment 20 christophe.lyon 2014-07-07 11:57:31 UTC
The problem was fixed by Jakub's commit 212289.
Thanks.
Comment 21 Jason Merrill 2014-08-01 18:53:48 UTC
Fixed in 4.9.1.
Comment 22 Cameron 2014-08-06 18:35:58 UTC
*** Bug 62036 has been marked as a duplicate of this bug. ***
Comment 23 Matthijs van Duin 2018-09-30 13:55:43 UTC
There appears to be a regression of this bug. See bug 70792.
Comment 24 Jonathan Wakely 2018-10-01 12:49:33 UTC
There's no regression (see bug 70792 comment 5).

G++ still warns for the testcasese here, even though it produces the right code now.
Comment 25 Matthijs van Duin 2019-01-26 03:10:48 UTC
I wasn't referring to the warnings though but incorrect code generation. Since is exhibited by pretty trivial test cases (testsuite/g++.dg/cpp0x/initlist86.C confirms that { i++, i++ } works but the analogous test for { ++i, ++i } fails) yet was first reported long after this bug was marked "FIXED" I kind of assumed it was a regression, but apparently it was just never really fixed to begin with.