Bug 108788 - Lookup of injected class name should be type-dependent
Summary: Lookup of injected class name should be type-dependent
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 13.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2023-02-14 16:33 UTC by m.cencora
Modified: 2023-10-17 03:15 UTC (History)
3 users (show)

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


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description m.cencora 2023-02-14 16:33:20 UTC
Following code fails to compile on any gcc version. Works on all clang versions.

It looks like inside template function get_templ_base the lookup of v.templ_base::a is done eagerly, and finds templ_base at the global scope, and hence errors out because the template parameters are missing.
But at this point qualified name "templ_base::a" should be type-dependent, so lookup should be delayed until template instantiation, where 'templ_base' is an injected class name, so template paremeters shouldn't be required.

g++ -std=c++11

struct base
{
    int a = 1;
};

template <typename T>
struct templ_base
{
    int a = 2;
};

namespace bar
{
    
struct base2
{
    int a = 3;
};

template <typename T>
struct templ_base2
{
    int a = 4;
};


}

struct foo : base, bar::templ_base2<char>, templ_base<int>, bar::base2
{
    int base = 5;
    int templ_base = 6;
    int base2 = 7;
    int templ_base2 = 8;
    int a = 9;
};

static_assert(foo{}.base::a == 1, "");
static_assert(foo{}.templ_base::a == 2, "");
static_assert(foo{}.base2::a == 3, "");
static_assert(foo{}.templ_base2::a == 4, "");


template <typename T>
int get_base(T&& v)
{
    return v.base::a;
}

template <typename T>
int get_templ_base(T&& v)
{
    return v.templ_base::a; // fails in all gcc versions
}

template <typename T>
int get_base2(T&& v)
{
    return v.base2::a; // fails for gcc <= 11
}

template <typename T>
int get_templ_base2(T&& v)
{
    return v.templ_base2::a;  // fails for gcc <= 11
}

int a = get_base(foo{});
int b = get_templ_base(foo{});
int c = get_base2(foo{});
int d = get_templ_base2(foo{});
Comment 1 Andrew Pinski 2023-02-14 20:12:12 UTC
I suspect this is related to the C++ paper:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1787r6.html
Comment 2 Patrick Palka 2023-05-19 18:24:38 UTC
Partially fixed by r12-3643-g18b57c1d4a8777.  Reduced version of what we still reject:

template <typename T>
struct templ_base { };

template <typename T>
int get_templ_base(T&& v)
{
    return v.templ_base::a; // fails in all gcc versions
}

<stdin>: In function ‘int get_templ_base(T&&)’:
<stdin>:7:14: error: ‘template<class T> struct templ_base’ used without template arguments