Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clang vs MSVC: Treatment of template function prototypes

The following is a piece of test code, and I'm comparing the result of compiling this with MSVC and Clang respectively. The output of each compiler is shown below. MSVC pretends that the unused template declaration doesn't even exist. Clang produces an error. The question is, which compiler is most standard conformant here?

I have seen legacy production code that relies on the MSVC behavior, and I'm unsure whether or not it can continue to be relied on.

class S
{
    struct P {};
};

template<typename T>
S::P Bat(T);

Compiles cleanly in MSVC10:

E:\clangbuild\bin\Release>cl /c /nologo test.cpp
test.cpp

Produces an error in Clang:

E:\clangbuild\bin\Release>clang++ test.cpp
test.cpp:9:4: error: 'P' is a private member of 'S'
S::P Bat(T);
   ^
test.cpp:5:9: note: implicitly declared private here
struct P {};
        ^
1 error generated.
like image 814
brendanw Avatar asked Feb 16 '12 00:02

brendanw


1 Answers

This fails because of the two-phase name lookup in C++.

In phase one, when the template is initially parsed, long before it is instantiated, the compiler parses the template and looks up any non-dependent names. S::P is a non-dependent name, so the compiler tries to look it up, but fails because it is private.

In phase 2, when the template is instantiated, the compiler will lookup any dependent names, which can vary from template to template.

Clang is fairly strictly conforming to the two-phase name lookup. However, MSVC has a template parsing model that delays nearly every lookup to instantiation time, which is part of phase 2. This delay is why your example would compile with MSVC(which is non-conforming) and not in clang. Here is a link with more information:

The Dreaded Two-Phase Name Lookup

Also, here are the sections from the C++ standard where it describes the two-phase lookup.

14.6.8:

When looking for the declaration of a name used in a template definition, the usual lookup rules (3.4.1, 3.4.2) are used for non-dependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known.

14.6.9:

If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation.

Then the part of 3.4 Name lookup applicable to you:

The access rules (clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing (clause 5).

Its clear from reading these parts that your program is ill-formed. The only thing the standard states that should be postponed until instantiation is the lookup of a dependent name. Non-dependent names go through the usual name lookup, which includes access rules.

like image 144
Paul Fultz II Avatar answered Oct 22 '22 17:10

Paul Fultz II