Implicit conversion yields "error: taking address of temporary" (GCC vs clang)

Viewed 133

While experimenting with strongly typed integers, I have experienced a weird error from GCC 8.2:

error: taking address of temporary

I can imagine typical scenarios where the above error makes sense, but in my case I do not get the problem. A minified (contrived) example which reproduces the error is the following:

#include <cstddef>

#include <type_traits>

enum class Enum : std::size_t {};

struct Pod {
  std::size_t val;

  constexpr operator Enum() const {
    return static_cast<Enum>(val);
  }
};

template<std::size_t N>
constexpr void foo() {
  using Foo = std::integral_constant<Enum, Pod{N}>;
  // [GCC] error: taking address of temporary [-fpermissive]
}

int main() {
  foo<2>();
}

Why is GCC 8.2 complaining here? Clang 6.0 is happy (see goldbolt.org).

Note that there is a second error from GCC which may help to analyze the problem. I do not understand that either:

error: no matching function for call to Pod::operator Enum(Pod*)

The complete output from GCC 8.2 reads

<source>: In instantiation of 'constexpr void foo() [with long unsigned int N = 2]':

<source>:22:10:   required from here

<source>:17:50: error: taking address of temporary [-fpermissive]

   using Foo = std::integral_constant<Enum, Pod{N}>;

                                                  ^

<source>:17:50: error: no matching function for call to 'Pod::operator Enum(Pod*)'

<source>:10:13: note: candidate: 'constexpr Pod::operator Enum() const'

   constexpr operator Enum() const {

             ^~~~~~~~

<source>:10:13: note:   candidate expects 0 arguments, 1 provided

Compiler returned: 1
1 Answers

This is obviously a bug; 'Pod::operator Enum(Pod*)' is nonsense. You cannot pass arguments to operator Enum.

The compiler seems to think that the right operation to convert a Foo to an Enum at compiler time is foo.operator Enum(&foo) or something. That both explains the "address of temporary" and the next line.

Related