Search code examples
c++gccsequence-points

Sequence point compiler warning only in gcc but not in clang


Consider the following code:

#include <tuple>

struct A {
  template <typename... Types> operator std::tuple<Types...>() {
    int i = 0;
    return std::tuple<Types...>{Types(i++)...};
  }
};

struct B {
  B(int i){};
};

int main() {
  A a;
  std::tuple<B, B> t{a};
}

It produces the following warnings in gcc

$ g++-12 main.cpp -std=c++20 -Wall                                                                                                                                
main.cpp: In instantiation of ‘A::operator std::tuple<_UTypes ...>() [with Types = {B, B}]’:
main.cpp:18:23:   required from here
main.cpp:7:46: warning: operation on ‘i’ may be undefined [-Wsequence-point]
    7 |     return std::tuple<Types...>{Types(i++)...};
      |                                              ^
main.cpp:7:46: warning: operation on ‘i’ may be undefined [-Wsequence-point]

but not in clang:

clang++-14 main.cpp -std=c++20 -Wall                                                                                                                                            
main.cpp:18:20: warning: unused variable 't' [-Wunused-variable]
  std::tuple<B, B> t{a};
                   ^
1 warning generated.

Why?

This may be related but the referenced gcc bug is already fixed. I have gcc --version gcc (Debian 12.2.0-9) 12.2.0.


Solution

  • The order of evaluation of elements in a braced-init-list is strictly left-to-right, already since C++11, and regardless of the context in which the syntax is used. See https://timsong-cpp.github.io/cppwp/n3337/dcl.decl#dcl.init.list-4.

    So the warning is bogus. @Artyer linked this bug report for a false positive warning under the question, which probably covers your example as well.

    As mentioned in the other bug report you linked, GCC had actual wrong code generation for similar cases in earlier versions though, so you might want to be careful when relying on this order.