Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 365981 - CDT fails to remove overload from overload set due to substitution error
Summary: CDT fails to remove overload from overload set due to substitution error
Status: RESOLVED FIXED
Alias: None
Product: CDT
Classification: Tools
Component: cdt-parser (show other bugs)
Version: 8.0.1   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 8.0.2   Edit
Assignee: Markus Schorn CLA
QA Contact: Markus Schorn CLA
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-12-07 22:31 EST by Nathan Ridge CLA
Modified: 2012-01-02 08:22 EST (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nathan Ridge CLA 2011-12-07 22:31:05 EST
In the following code:

template <typename T>
void foo(T);

template <typename T>
void foo(T, typename T::type* = 0);

int main()
{
    foo(0);  // ERROR HERE
}

the substitution of 'int' into the second overload causes a substitution error (because int::type is not well-formed) and should remove the candidate from the overload set. The call should therefore resolve unambiguously to the first overload.

However, CDT gives the following error at the call site:

'foo' is ambiguous '
Candidates are:
void foo(int, #0::type *)
void foo(int)
'

suggesting that it does not remove the second overload from the overload set.
Comment 1 Markus Schorn CLA 2011-12-22 05:31:02 EST
Thanks, added testcase and fix.
Comment 2 Nathan Ridge CLA 2011-12-26 19:35:17 EST
OK, the test case above now works, but something slightly more complicated still fails:


template <bool, typename _Tp = void>
struct enable_if
{
};

template <typename _Tp>
struct enable_if<true, _Tp>
{
    typedef _Tp type;
};

template <typename T, typename Signature>
struct has_foo
{
    template <typename U, U> struct type_check;
    template <typename X> static char (& chk(type_check<Signature, &X::foo> *))[1];
    template <typename  > static char (& chk(...))[2];
    static bool const value = sizeof(chk<T>(0)) == 1;
};

template <typename T>
bool bar(T);

template <typename T>
bool bar(T, typename enable_if<has_foo<T, void(T::*)()>::value>::type* = 0);

int main()
{
    bar(0);  // ERROR HERE: 'bar' is ambiguous
}


Here, has_foo<int, void(T::*)()>::value evaluates to false, and enable_if<false> does not have a nested 'type' member, so the substitution of 'int' into the second overload causes a substitution error, and so the second overload should be removed from the overload set.
Comment 3 Nathan Ridge CLA 2011-12-26 19:40:22 EST
Simplified testcase:


template <bool, typename _Tp = void>
struct enable_if
{
};

template <typename _Tp>
struct enable_if<true, _Tp>
{
    typedef _Tp type;
};

template <typename T>
struct has_foo
{
    static bool const value = false;
};

template <typename T>
bool bar(T);

template <typename T>
bool bar(T, typename enable_if<has_foo<T>::value>::type* = 0);

int main()
{
    bar();
}
Comment 4 Nathan Ridge CLA 2011-12-26 19:46:22 EST
Sorry, please ignore the "simplified testcase" in the previous comment, it is wrong.
Comment 5 Nathan Ridge CLA 2011-12-26 19:52:44 EST
Please also ignore my description of why the substitution failure occurs in comment #2, that was incorrect too :(

Here is a correct, and much more simplified, testcase:


template <typename T>
bool bar(T);

template <typename T>
bool bar(T, void(T::*)() = 0);

int main()
{
    bar(0);  // ERROR HERE: 'bar' is ambiguous
}


Here, the substitution failure occurs because 'void(T::*)()' is ill-formed when T = int.
Comment 6 Markus Schorn CLA 2012-01-02 08:22:21 EST
Thanks for the example!
This is actually a different bug, for which it is usually better to open a new bug report.

Added further testcase and fix.