c++language-lawyerc++20c++-modules

What is decl-reachable in C++ 20?


§10.4/3 gives all the possible situations of decl-reachable in detail. However, I can't fully understand it. Consider the example described in §10.4/6: Source file foo.h:

namespace N {
  struct X {};
  int d();
  int e();
  inline int f(X, int = d()) { return e(); }
  int g(X);
  int h(X);
}

Module M interface:

module;
#include "foo.h"
export module M;
template<typename T> int use_f() {
  N::X x;                       // N​::​X, N, and ​::​ are decl-reachable from use_­f
  return f(x, 123);             // N​::​f is decl-reachable from use_­f,
                                // N​::​e is indirectly decl-reachable from use_­f
                                //   because it is decl-reachable from N​::​f, and
                                // N​::​d is decl-reachable from use_­f
                                //   because it is decl-reachable from N​::​f
                                //   even though it is not used in this call
}
template<typename T> int use_g() {
  N::X x;                       // N​::​X, N, and ​::​ are decl-reachable from use_­g
  return g((T(), x));           // N​::​g is not decl-reachable from use_­g
}
template<typename T> int use_h() {
  N::X x;                       // N​::​X, N, and ​::​ are decl-reachable from use_­h
  return h((T(), x));           // N​::​h is not decl-reachable from use_­h, but
                                // N​::​h is decl-reachable from use_­h<int>
}
int k = use_h<int>();
  // use_­h<int> is decl-reachable from k, so
  // N​::​h is decl-reachable from k

Module M implementation:
module M;
int a = use_f<int>();           // OK
int b = use_g<int>();           // error: no viable function for call to g;
                                // g is not decl-reachable from purview of
                                // module M's interface, so is discarded
int c = use_h<int>();           // OK

Why is N​::​g not decl-reachable from use_­g? Why is N​::​h not decl-reachable from use_­h, but N​::​h is decl-reachable from use_­h<int>? Why doesn't §10.4/(3.2) or §10.4/(3.3) apply to them?


Solution

  • N::f is decl-reachable from use_f due to rule 10.4.3.2.

    In determining whether N::g is reachable from use_g, we find that neither 10.4.3.2 nor 10.4.3.3 applies.

    For similar reasons, N::h is not decl-reachable from use_h.

    When use_h<int> is instantiated, then rule 10.4.3.2 applies. At that point, the compiler determines that the type of (T(), x) is N::X, and actually performs the name lookup for h, finding N::h through argument-dependent lookup. That is, h((T(), x)) names the function N::h in this particular specialization (where T = int), but not in the original template.