https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98283

            Bug ID: 98283
           Summary: decltype(auto) may be deduce static data member to
                    wrong type
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: wuyongwei at gmail dot com
  Target Milestone: ---

The following code shows that `decltype(auto)` is deduced to the wrong type
when used in template code for an expression like `(var.static_data_member>)`.

```cpp
#include <cstddef>
#include <type_traits>
#include <utility>

template <typename T>
struct type_displayer;

#define TYPE_DISPLAY(x) type_displayer<decltype(x)> test_obj;

struct SkipField {};

struct TestSkip {
    template <typename T, std::size_t> struct FIELD;

    int value;
    static SkipField unused;

    template <typename T>
    struct FIELD<T, 0> {
        T &&obj;
        FIELD(T &&ref) : obj(std::forward<T>(ref))
        {
        }
        decltype(auto) value()
        {
            return (obj.value);
        }
        static constexpr const char *name()
        {
            return "value";
        }
    };

    template <typename T>
    struct FIELD<T, 0 + 1> {
        T &&obj;
        FIELD(T &&ref) : obj(std::forward<T>(ref))
        {
        }
        decltype(auto) value()
        {
            return (obj.unused);
        }
        decltype((obj.unused)) valueAlt()
        {
            return (obj.unused);
        }
        static constexpr const char *name()
        {
            return "unused";
        }
    };
};

int main()
{
    TestSkip s;
    // decltype((TestSkip::FIELD<TestSkip&, 0>(s).value()))    is int&
    // decltype((TestSkip::FIELD<TestSkip&, 1>(s).value()))    is SkipField,
but it should be SkipField&
    // decltype((TestSkip::FIELD<TestSkip&, 1>(s).valueAlt())) is SkipField&
}
```

This is a simplified usage scenario, where I want to use a macro to generate
code to emulate static reflection. Here is the problematic part:

```cpp
        decltype(auto) value()
        {
            return (obj.unused);
        }
```

This function returns `SkipField`, instead of the expected `SkipField&`. I have
verified that clang does what I want.

Currently I have to avoid `decltype(auto)` as a workaround:

```cpp
        decltype((obj.unused)) valueAlt()
        {
            return (obj.unused);
        }
```

(I used the macro TYPE_DISPLAY to check the type of an expression.)

Reply via email to