Bug 55159

Summary: pythy constexpr auto lambda pointer has no initializer
Product: gcc Reporter: supercilious.dude
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: daniel.kruegler, paolo.carlini
Priority: P3    
Version: unknown   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2012-11-07 00:00:00
Bug Depends on:    
Bug Blocks: 55004    

Description supercilious.dude 2012-11-01 00:33:27 UTC
Pythy (http://pfultz2.github.com/Pythy/) does something akin to:

template <typename T> 
typename std::remove_reference<T>::type *addr(T &&t) 
{ 
    return &t; 
}

template <class T0, class T1>
struct min_t
{
    constexpr static auto *f =
        false ? addr([](T0 x, T1 y){ return x < y ? x : y; }) : nullptr; 
};

Which gcc (4.7.2 and 4.8.0 git master) cannot evaluate.
clang and visual studio 2012 work fine.

I know this is not strictly needed by gcc 4.8 since it has deduced auto without the late specifier (which the other compilers lack), but its highly convenient to have pythy work on all c++11 compilers.
Comment 1 Daniel Krügler 2012-11-01 10:58:06 UTC
I really think that Pythy should fix this implementation, because it is not supported by the C++11 standard. Any compiler accepting that is defect. According to 9.4.2 p3:

"A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression."

As of 5.19 p2 the appearance of a lambda-expression prevents an expression from satisfying the requirements of a (core) constant expression.

But changing your example to

template <typename T>
T* addr(T& t) { return &t; }

bool less(int x, int y) { return x < y ? x : y; }

const static auto* f = addr(less);

indeed points to a defect of gcc, not being able to deduce auto here. I think this is the same bug that I can remember (but cannot find at the very moment) which shows a similar problem during overload resolution in templates when involving function addresses such as in

template <typename T>
T* addr(T& t) { return &t; }

bool less(int x, int y) { return x < y ? x : y; }

template<typename T>
int deduce(const T*) { return 0; }

int i = deduce(addr(less));

This example should be accepted, but gcc doesn't like it saying:

"error: no matching function for call to 'deduce(bool (*)(int, int))'|
note: candidate is:|
note: template<class T> int deduce(const T*)|
note:   template argument deduction/substitution failed:|
note:   types 'const T' and 'bool(int, int)' have incompatible cv-qualifiers"
Comment 2 Paolo Carlini 2012-11-01 14:25:26 UTC
Daniel, you mean PR54111 maybe?
Comment 3 Daniel Krügler 2012-11-01 15:11:51 UTC
(In reply to comment #2)
Hmmh, it doesn't look like that one, maybe I was wrong about an existing issue.

But it seems that gcc doesn't ignore the const (in "const T*" or "const auto*") for functions here, which seems to be the root of the second problem (This is *not* attempting to form a function with cv-qualifier-seq). Both

template <typename T>
T* addr(T& t) { return &t; }

bool less(int x, int y) { return x < y ? x : y; }

static auto* f = addr(less);

and

template <typename T>
T* addr(T& t) { return &t; }

bool less(int x, int y) { return x < y ? x : y; }

template<typename T>
int deduce(T*) { return 0; }

int i = deduce(addr(less));

are accepted as they should.
Comment 4 Daniel Krügler 2012-11-02 08:10:14 UTC
(In reply to comment #3)
> But it seems that gcc doesn't ignore the const (in "const T*" or "const auto*")
> for functions here, which seems to be the root of the second problem (This is
> *not* attempting to form a function with cv-qualifier-seq).

I withdraw my interpretation that it is *clear* here that during template argument deduction we can successfully match a "const T" with a function type. This looks like a core language problem to me and I'll notify CWG in regard to this.
Comment 5 Daniel Krügler 2012-11-02 08:57:33 UTC
I need to insert another correction. My attempt to simplify the reporters bug failed because I was mislead by the report description that "visual studio 2012 work fine" interpreting this to mean the Microsoft Visual Studio 2012 compiler. But that one does not understand 'constexpr' therefore my reduction to 'const' was not equivalent.

(In reply to comment #1)
> I really think that Pythy should fix this implementation, because it is not
> supported by the C++11 standard. Any compiler accepting that is defect.

This statement still holds. The original code is not conforming.

The following presents a conforming code that reproduces the problem:

template <class T0, class T1>
struct min_t
{
    static bool less(T0 x, T1 y) { return x < y ? x : y; }
    constexpr static auto* f = &less; // #5
};

min_t<int, int> mi; // #8

"8|  required from here|
5|error: declaration of 'constexpr auto* const min_t<int, int>::f' has no initializer"

Please ignore the part about const T in template deduction. This is a different issue and not related to this one.
Comment 6 Paolo Carlini 2012-11-02 11:14:54 UTC
Thus, Daniel, is this invalid?
Comment 7 Daniel Krügler 2012-11-02 11:39:07 UTC
(In reply to comment #6)
> Thus, Daniel, is this invalid?

I think this part of the problem is indeed valid:

template <class T0, class T1>
struct min_t
{
    static bool less(T0 x, T1 y) { return x < y ? x : y; }
    constexpr static auto* f = &less; // #5
};

min_t<int, int> mi; // #8

"8|  required from here|
5|error: declaration of 'constexpr auto* const min_t<int, int>::f' has no
initializer"

(With or without & in front of less)

According to my understanding this should be accepted.
Comment 8 Paolo Carlini 2012-11-02 11:48:39 UTC
Ah, Ok, I was a bit lost ;) Thanks. However, my (very rough) feeling is that we have got already quite a bit in Bugzilla in the area, constexpr, auto, pointers...
Comment 9 Paolo Carlini 2012-11-07 15:42:04 UTC
Uhm, for testcase in Comment #7 we call finish_static_data_member_decl from instantiate_class_template_1 and we explicitly pass init == NULL_TREE, no chances for things to work from this point on. Interestingly this is the *only* place in pt.c where we call finish_static_data_member_decl.
Comment 10 Paolo Carlini 2012-11-07 16:11:28 UTC
Oh, Comment #7 is really the same as PR55003.

*** This bug has been marked as a duplicate of bug 55003 ***