-1

In a library of mine, I have the following bit of code (snipped for brevity):

namespace memory {
namespace managed {

namespace detail {

template <typename T>
inline T get_scalar_range_attribute(
    region_t region,
    cudaMemRangeAttribute attribute)
{ /* snip */ }

} // namespace detail

struct region_t : public memory::region_t {
    // snip
    bool is_read_mostly() const
    {
        return detail::get_scalar_range_attribute<bool>(
            *this, cudaMemRangeAttributeReadMostly);
    }

    // snip
}

} // namespace managed
} // namespace memory

Now, with GCC and Clang on Linux, this works fine. But with MSVC 16.8.4 on Windows, a user of mine gets:

error : template instantiation resulted in unexpected function type of "__nv_bool
(cuda::memory::managed::region_t, cudaMemRangeAttribute)" (the meaning of a name
may have changed since the template declaration -- the type of the template is "T
(cuda::memory::region_t, cudaMemRangeAttribute)"

I don't understand how an instantiation can result in something unexpected, ever. I also don't see how my "name hiding" of one class name with another should have any effect on the template instantiation.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • Did you meant `get_scalar_range_attribute(memory::region_t region, cudaMemRangeAttribute attribute)`? – Guillaume Racicot Feb 08 '21 at 14:18
  • Also try to compile with `/permissive-` – Guillaume Racicot Feb 08 '21 at 14:20
  • @GuillaumeRacicot: 1. Yes, but that's the only `region_t` possible at that point. Do you think that's the issue? 2. This is a header part of the library, and I can't tell people to compile with permissive... I need to satisfy the stricter compiler. – einpoklum Feb 08 '21 at 21:06
  • ... ah, but I guess I am making the implicit assumption that it's a managed memory range. OK. – einpoklum Feb 08 '21 at 21:24
  • 1
    You misunderstood. `/permissive-` (spelled permissive minus) disable permissive on MSVC. Yes, MSVC compiles with permissive by default and you must disable it. – Guillaume Racicot Feb 08 '21 at 22:18
  • What you say points directly to the flag permissive minus: By default, MSVC don't support two phase name lookup. That means that **all name lookup happens at the instantiation without `/permissive-`**. This is also why MSVC had multiple bugs not selecting the right function in templates. – Guillaume Racicot Feb 08 '21 at 22:20
  • Hmm. But if all lookup occurs at instantiation - why does MSVC mind the change between declaration time and instantiation time? It is effectively less permissive than the "permissive" mode... isn't it? – einpoklum Feb 08 '21 at 22:23
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/228437/discussion-between-guillaume-racicot-and-einpoklum). – Guillaume Racicot Feb 08 '21 at 22:35

1 Answers1

1

(Credit goes to @Guillaume Racicot for most of this.)

The issue here is the timing of name lookup.

Other compiles, when encountering the template declaration, region_t, seem to look for previously-defined region_t's; find memory::region_t; and be ok with that. (Correct me if I'm wrong).

MSVC, however, performs the lookup twice: Once when encountering the declaration+definition, then again upon instantiation - with different contexts both times. So, the first time, it finds memory::region_t; and the second time it finds memory::managed::region_t. This is "unexpected"...

This behavior of MSVC is apparently due to its "permissive" compilation mode (which is enabled by default). This is a bit weird, seeing how it is less permissive in this case, but that's just how it is.

einpoklum
  • 118,144
  • 57
  • 340
  • 684