Search code examples
c++visual-studiogccnamespacesname-lookup

Who is correct here, GCC or MSVC?


Suppose we have this structure:

namespace some_namespace::types {
    using foo_t = int;
}

namespace some_namespace::classes {
    class bar {
    public:
        auto do_stuff() -> types::foo_t;
    };
}

using namespace some_namespace::classes;

auto bar::do_stuff() -> types::foo_t {
    return 1;
}

This code compiles happily in GCC6.
On the other hand, VS15 with the /std:c++latest switch enabled doesn't recognize the return type of do_stuff. It returns C2653.

Now, what I find highly suspicious is that this gets fixed by changing the second half to this:

using namespace some_namespace;

auto classes::bar::do_stuff() -> types::foo_t {
    return 1;
}

which in my eyes should be equal. Am I mistaken in thinking that this is a MSVC bug? What does the standard say about this?


Solution

  • This has nothing to do with the C++17 feature, which didn't touch using-directives, nor indeed with using-directives at all. MSVC produces the same error from

    namespace some_namespace{
        namespace types {
            using foo_t = int;
        }
        namespace classes {
            class bar {
            public:
                auto do_stuff() -> types::foo_t;
            };
        }
    }
    
    using some_namespace::classes::bar;
    
    auto bar::do_stuff() -> types::foo_t {
        return 1;
    }
    

    [basic.lookup.unqual]/8:

    For the members of a class X, a name used [...] in the definition of a class member outside of the definition of X, following the member's declarator-id, shall be declared in one of the following ways:

    • before its use in the block in which it is used or in an enclosing block ([stmt.block]), or

    • shall be a member of class X or be a member of a base class of X ([class.member.lookup]), or

    • [...two bullet points about nested and local classes omitted...]

    • if X is a member of namespace N [...], before the use of the name, in namespace N or in one of N's enclosing namespaces.

    Name lookup for types should first look inside bar, then inside classes, then inside some_namespace. That last one should find the namespace types.