Bug 28330 - finds wrong template overload; peculiar diagnostic
Summary: finds wrong template overload; peculiar diagnostic
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.0.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-07-10 20:10 UTC by Ivan Godard
Modified: 2009-12-08 21:06 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
compiler output -v (1022 bytes, application/octet-stream)
2006-07-10 20:11 UTC, Ivan Godard
Details
save-temps source (compressed) (182.48 KB, application/gzip)
2006-07-10 20:11 UTC, Ivan Godard
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ivan Godard 2006-07-10 20:10:46 UTC
The error is an invocation of operator<<(ring<cacheRequest>&, loadRequest*).
ring<cacheRequest> defines operator<<(ring<cacheRequest>&, cacheRequest*), and 
cacheRequest is a public base of the actual loadRequest argument. If the right 
argument is explicitly cast to cacheRequest* (as shown in the line immediately 
before the reported error) the correct operator<< is found and invoked.

However, when the argument is the derived class the compiler finds and invokes 
an irrelevant definition of operator<< and then blows up inside it. The 
definition it finds is declared by template wideUint<size_t> and in particular 
by wideUint<1>: operator<<(wideUint<1>, const uint32_t&). Somehow it seems to 
decide that it can turn a ring<cacheRequest>& into a wideUint<1>, and then 
complains that it can't turn a cacheRequest* into a uint32_t (which is a typedef 
for unsigned int).

It seems to me that the compiler should be able to match the intended operator 
by converting to the base class. However, even if it cannot then shouldn't it 
just say "no match found for ..." rather than accepting the bogus match and then 
complaining about the conversion to uint32_t?
Comment 1 Ivan Godard 2006-07-10 20:11:25 UTC
Created attachment 11855 [details]
compiler output -v
Comment 2 Ivan Godard 2006-07-10 20:11:53 UTC
Created attachment 11856 [details]
save-temps source (compressed)
Comment 3 Wolfgang Bangerth 2006-07-11 08:29:10 UTC
As usual, a reduced (or at least smaller than 51,000 lines) testcase would be supremely helpful...

W.
Comment 4 Harald van Dijk 2008-03-02 10:57:05 UTC
I only came across this bug looking for something else, but anyway, here's a reduced testcase:

template <typename T>
class ring {};

template <typename T>
ring<T> &operator<<(ring<T>&, T *);

class base {};
class derived : public base {};

void f() {
  ring<base> r;
  derived *d;
  r << d;
}

I believe this code is invalid. The template argument can't be deduced, and you'd need something like

template <typename T>
class ring {};

template <typename T>
struct non_deducible { typename T type; };

template <typename T>
ring<T> &operator<<(ring<T>&, typename non_deducible<T>::type *);

so that only the first argument is considered when choosing which T to use.

Or, more simply, make operator<< a member function.
Comment 5 Jonathan Wakely 2009-12-08 21:06:52 UTC
Assuming that's an accurate reduction of the original code, comment 4 is correct.  I didn't look at the preprocessed source, it includes Boost code that will be very specific to the GCC 4.0.2 version it was compiled with and so useless with any other version of GCC