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

            Bug ID: 83596
           Summary: ['17] can't use member pointer result of a constexpr
                    function as template argument
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: oremanj at mit dot edu
  Target Milestone: ---

The below C++ program defines a constexpr function that returns a
pointer-to-member, then attempts to use that pointer-to-member as a template
argument. I believe this is fine by the standard, and clang (5.0.0) accepts it,
but gcc complains, in a fashion that suggests there's some internal confusion
about types going on.

$ cat t.cc
struct X { int x; int y; };
template <int X::* mp> int get(X& x) { return x.*mp; }
constexpr int X::* getMP() { return &X::y; }
constexpr int X::* mptr = getMP();
int test() {
    X x{1, 2};
    return get<mptr>(x);
}

$ g++ -std=c++17 -c t.cc
t.cc: In function 'int test()':
t.cc:7:23: error: no matching function for call to 'get<mptr>(X&)'
    return get<mptr>(x);
                       ^
t.cc:2:28: note: candidate: template<int X::* mp> int get(X&)
template <int X::* mp> int get(X& x) { return x.*mp; }
                           ^~~
t.cc:2:28: note:   template argument deduction/substitution failed:
t.cc:7:23: error: '4' is not a valid template argument for type 'int X::*'
    return get<mptr>(x);
                      ^
t.cc:7:23: note: it must be a pointer-to-member of the form '&X::Y'

$ g++ --version
g++ (GCC-Explorer-Build) 8.0.0 20171226 (experimental)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

The error is unchanged under any of the following perturbations:
- every 'int X::*' is replaced by 'auto'
- the result of getMP() is passed as the template argument directly
- mptr is defined as &X::y directly, getMP() is defined to return mptr, and
get() is instantiated with <getMP()> as its argument
- optimizations are used or not used
- either getMP() or mptr is assigned to a local-scope constexpr in test() which
is then used as the template argument

Compilation succeeds if there is no constexpr function involved, e.g. if the
source file says 'constexpr int X::* mptr = &X::y;' directly.

gcc 7.2.1 returns a slightly different error message; the final "note:" above
is replaced with

t.cc:7:23: error: it must be a pointer-to-member of the form '&X::Y'
t.cc:7:23: error: could not convert template argument 'mptr' from 'int X::*
const' to 'int X::*'

Reply via email to