c++language-lawyerc++23

Example in C++23 standard doesn't work in gcc?


In the unqualified name lookup, the standard gives the example 1.

struct T1 { struct U { int i; }; };
struct T2 { };
struct U1 {};
struct U2 {};

struct B {
  using T = T1;
  using U = U1;
  operator U1 T1::*();
  operator U1 T2::*();
  operator U2 T1::*();
  operator U2 T2::*();
};

template<class X, class T>
int g() {
  using U = U2;
  X().operator U T::*();                // #1, searches for T in the scope of X first
  X().operator U decltype(T())::*();    // #2
  return 0;
}
int x = g<B, T2>();                     // #1 calls B​::​operator U1 T1​::​*
                                        // #2 calls B​::​operator U1 T2​::​*

An unqualified name that is a component name ([expr.prim.id.unqual]) of a type-specifier or ptr-operator of a conversion-type-id is looked up in the same fashion as the conversion-function-id in which it appears. If that lookup finds nothing, it undergoes unqualified name lookup; in each case, only names that denote types or templates whose specializations are types are considered.

From the standard, it seems that the unqualified name U and T in operator U T::* shall be looked up in the same way as operator U T::*, i.e. looked up in the class scope B, so that the first call should be operator U1 T1::*. While the expression decltype(T()) will be instantiated to be T2, the second call should be operator U1 T2::*().

It shocks me so that I made an experiment by adding codes below and compiling it:

#include <iostream>

B::operator U1 T1::*()
{
    std::cout << __func__ << std::endl;
    return nullptr;
}
B::operator U1 T2::*()
{
    std::cout << __func__ << std::endl;
    return nullptr;
}
B::operator U2 T1::*()
{
    std::cout << __func__ << std::endl;
    return nullptr;
}
B::operator U2 T2::*()
{
    std::cout << __func__ << std::endl;
    return nullptr;
}
int main() {}

However, the result is

operator U2 T2::*
operator U2 T2::*

instead of by the standard

operator U1 T1::*
operator U1 T2::*

Why the behavior differs with standard? I find no Defect Report about this.

My g++ version is
g++.exe (x86_64-win32-seh-rev1, Built by MinGW-Builds project) 14.2.0


Solution

  • This has to do with the fact that lookup for dependent conversion-type-ids was never properly specified prior to C++23; see CWG1500. The rule you cite was added by P1787R6, which completely overhauled the specification of name lookup in the standard. Because so many changes were made, it will take a while for GCC to finish implementing all of them.