cplusplus / CWG

Core Working Group
23 stars 7 forks source link

[temp.res.general] p1 The program point `P` from which the name lookup is performed for a member name of a class that was dependent is unclear #407

Open xmh0511 opened 1 year ago

xmh0511 commented 1 year ago

Full name of submitter (unless configured in github; will be published with the issue): Jim X

[temp.res.general] p1 says

If the name is dependent (as specified in [temp.dep]), it is looked up for each specialization (after substitution) because the lookup depends on a template parameter.

Consider this formal example [module.context] p7:

Translation unit #1:export module stuff;
export template<typename T, typename U> void foo(T, U u) { auto v = u; }  // #1
export template<typename T, typename U> void bar(T, U u) { auto v = *u; }

Translation unit #2:export module M1;
import "defn.h";        // provides struct X {};
import stuff;
export template<typename T> void f(T t) {
  X x;
  foo(t, x);
}

Translation unit #3:export module M2;
import "decl.h";        // provides struct X; (not a definition)
import stuff;
export template<typename T> void g(T t) {
  X *x;
  bar(t, x);
}

Translation unit #4:import M1;
import M2;
void test() {
  f(0);
}

Within the call to f(0), the class type X is reachable, however, at #1, the initialization would call the copy/move constructor that is looked up in the scope of X for each specialization of foo as per [temp.res.general] p1, however, we didn't define the program point from which the name lookup would perform, according to [basic.lookup.class.member.lookup] p3

The declaration set is the result of a single search in the scope of C for N from immediately after the class-specifier of C if P is in a complete-class context of C or from P otherwise.

For name lookup of the member name of a class that was a dependent type, I asked @opensdh and he had given the explanation:

The general rule is [temp.res.general]/1: every name in a template is looked up from the template declaration. There's actually a bug here: dependent names that are members of a class do in fact need to be looked up from the instantiation context in order to find members of those classes.

However, this arises another question, there are multiple instantiation contexts for foo, if we consider each instantiation context a program point, then not every program point from which the declaration of the constructor is reachable.