Bug 55460 - Template-dependent name is not looked up at instantiation point
Summary: Template-dependent name is not looked up at instantiation point
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.6.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-11-25 00:38 UTC by Yuriy Solodkyy
Modified: 2012-11-25 20:46 UTC (History)
1 user (show)

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


Attachments
Code reproducing bug (893 bytes, text/plain)
2012-11-25 00:38 UTC, Yuriy Solodkyy
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Yuriy Solodkyy 2012-11-25 00:38:36 UTC
Created attachment 28768 [details]
Code reproducing bug

Howdy,

I think this is a bug in G++. I have a call to a template function filter(T) in a template context. filter() is further overloaded before the instantiation point. G++ 4.6.1 and 4.5.2 (both under MinGW, sorry, I don't have access to a more recent version) seems to resolve it at declaration point (see attachment for the exact code reproducing bug):

namespace my
{
    ...
    // A function template that by default behaves as identity
    template <typename P>
    typename std::remove_reference<P>::type 
    filter(P&& p) throw() { return std::move(p); }
    ...
} // of namespace my 

// Since this is unrestricted template, ADL won't work, so we have to stick 
// this overloaded operator building an expression template into the global scope
template <typename P1>
inline auto operator&(P1&& p1) throw()
        -> typename std::enable_if<
                        my::is_mine<P1>::value,
                        my::address<decltype(my::filter(std::forward<P1>(p1)))>
                    >::type
{
    // NOTE: call to filter depends on template argument, thus have to be
    //       resolved at instantiation point. But it doesn't!
    return my::address<decltype(my::filter(std::forward<P1>(p1)))>
                               (my::filter(std::forward<P1>(p1)));
}

// We now declare few more classes modeling our concept: var and ref
namespace my
{
    template <typename T> class var;
    template <typename T> class ref;
    ...
    // and specialize function filter on them
    template <typename T> inline ref<var<T>>   filter( var<T>& t) throw() 
    { return ref<var<T>>(t); }
} // of namespace my 

int main()
{
    my::var<int> h;
    auto&& a = &h;  // Instantiate expression template via overloaded operator&
    std::cout << typeid(a).name() << std::endl;
}

GCC 4.6.1 output is:

    N2my7addressINS_3varIiEEEE

which indicates that there is no ref<> applied to var<> in instantiation of address<>. Visual C++ 10 and 11 produce:

    struct my::address<struct my::ref<struct my::var<int> > >

which have ref<> in between and is what I was actually expecting to have.

If I move the definition of overloaded operator& after the second namespace my is closed, the ref<> does properly appear on top of the var<>.

Can you please have a look at this?
Thank you!
Comment 1 Andrew Pinski 2012-11-25 00:49:05 UTC
    // NOTE: call to filter depends on template argument, thus have to be
    //       resolved at instantiation point.
    // BUG:  But it doesn't!


I don't think this is true if it was using ADL, then it would be true but there is no ADL here so it only depends on the overloaded set that is done at the definition time.
Comment 2 Yuriy Solodkyy 2012-11-25 01:07:36 UTC
Not sure I understand your comment - ADL with respect to what: my::filter or the ::operator&? Can you elaborate please?
Comment 3 Andrew Pinski 2012-11-25 01:56:20 UTC
(In reply to comment #2)
> Not sure I understand your comment - ADL with respect to what: my::filter or
> the ::operator&? Can you elaborate please?

With respect to my::filter.  Since it is a qualified name, the overloaded set is only considered at definition time rather than instantiation too.
Comment 4 Jonathan Wakely 2012-11-25 20:46:06 UTC
Andrew is right, the standard says:

In an expression of the form:
  postfix-expression ( expression-listopt)
where the postfix-expression is an unqualified-id, the unqualified-id denotes a dependent name if [...]

Since my::filter is not an unqualified-id it is not a dependent name, so the usual lookup rules apply and only names declared before the template definition can be found.