Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -1410,19 +1410,22 @@ return cutOffParsing(); } - // C++03 [temp.explicit] 14.7.2/8: - // The usual access checking rules do not apply to names used to specify - // explicit instantiations. + // C++20 [temp.class.spec] 17.6.5/10: + // The usual access checking rules do not apply to non-dependent names used + // to specify template arguments of the simple-template-id of the partial + // specialization // - // As an extension we do not perform access checking on the names used to - // specify explicit specializations either. This is important to allow - // specializing traits classes for private types. + // C++20 [temp.explicit] 17.8/6: + // The usual access checking rules do not apply to names in a declaration + // of an explicit instantiation or explicit specialization, with + // the exception of names appearing in a function body, default argument, + // base-clause, member-specification, enumerator-list, or static data member + // or variable template initializer. // // Note that we don't suppress if this turns out to be an elaborated // type specifier. bool shouldDelayDiagsInTag = - (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate; SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag); ParsedAttributesWithRange attrs(AttrFactory); @@ -1768,14 +1771,6 @@ } } - // If this is an elaborated type specifier, and we delayed - // diagnostics before, just merge them into the current pool. - if (shouldDelayDiagsInTag) { - diagsFromTag.done(); - if (TUK == Sema::TUK_Reference) - diagsFromTag.redelay(); - } - if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || TUK != Sema::TUK_Definition)) { if (DS.getTypeSpecType() != DeclSpec::TST_error) { @@ -1948,6 +1943,14 @@ } } + // If this is an elaborated type specifier, and we delayed + // diagnostics before, just merge them into the current pool. + if (shouldDelayDiagsInTag) { + diagsFromTag.done(); + if (TUK == Sema::TUK_Reference) + diagsFromTag.redelay(); + } + // If there is a body, parse it and inform the actions module. if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || Index: clang/test/CXX/temp/temp.decls/temp.class.spec/p10.cpp =================================================================== --- /dev/null +++ clang/test/CXX/temp/temp.decls/temp.class.spec/p10.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +// C++20 [temp.class.spec] 17.6.5/10: +// The usual access checking rules do not apply to non-dependent names used +// to specify template arguments of the simple-template-id of the partial +// specialization. + +class TestClass { +private: + void func(); + void funcOverloaded(); + void funcOverloaded(int); + + static void staticFunc(); + static void staticFuncOverloaded(); + static void staticFuncOverloaded(int); + + class Nested {}; + + int field; +}; + +template class TemplateClass {}; +template <> class TemplateClass<&TestClass::func> {}; +template <> class TemplateClass<&TestClass::funcOverloaded> {}; + +template class TemplateClass2 { }; +template <> class TemplateClass2<&TestClass::staticFunc> {}; +template <> class TemplateClass2<&TestClass::staticFuncOverloaded> {}; + +template class TemplateClass3 {}; +template class TemplateClass3 {}; +template class TemplateClass3 {}; + +template class TemplateClass4 {}; +template class TemplateClass4 {}; +template class TemplateClass4 {}; + +template class TemplateClass5 {}; +template<> class TemplateClass5 {}; + +template class TemplateClass6 {}; +template class TemplateClass6 {}; + +template class TemplateClass7 {}; +template <> class TemplateClass7<&TestClass::field> {}; + +template class TemplateClass8 {}; +template class TemplateClass8 {}; + +template +struct trait; + +class class_ { + template + struct impl; +}; + +template +struct trait>; Index: clang/test/CXX/temp/temp.spec/p6.cpp =================================================================== --- /dev/null +++ clang/test/CXX/temp/temp.spec/p6.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +class X { + template class Y {}; +}; + +class A { + class B {}; + class C {}; + + void func(); + static void staticFunc(); + + // See https://llvm.org/PR37424 + void funcOverloaded(); + void funcOverloaded(int); + static void staticFuncOverloaded(); + static void staticFuncOverloaded(int); + + int field; +}; + +// C++20 [temp.spec] 17.8/6: +// The usual access checking rules do not apply to names in a declaration of +// an explicit instantiation or explicit specialization, with the exception +// of names appearing in a function body, default argument, base-clause, +// member-specification, enumerator-list, or static data member or variable +// template initializer. +template class X::Y; + +template class D {}; +template class D<&A::func>; +template class D<&A::funcOverloaded>; + +template class E { }; +template class E<&A::staticFunc>; +template class E<&A::staticFuncOverloaded>; + +template class G {}; +template class G<&A::field>; + +// As an extension, this rule is applied to explicit specializations as well. +template <> class X::Y {}; Index: clang/test/CXX/temp/temp.spec/temp.explicit/p11.cpp =================================================================== --- clang/test/CXX/temp/temp.spec/temp.explicit/p11.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics - -class X { - template class Y {}; -}; - -class A { - class B {}; - class C {}; -}; - -// C++0x [temp.explicit] 14.7.2/11: -// The usual access checking rules do not apply to names used to specify -// explicit instantiations. -template class X::Y; - -// As an extension, this rule is applied to explicit specializations as well. -template <> class X::Y {}; Index: clang/www/cxx_status.html =================================================================== --- clang/www/cxx_status.html +++ clang/www/cxx_status.html @@ -966,7 +966,7 @@ Access checking on specializations P0692R1 - Partial + Clang 11 Default constructible and assignable stateless lambdas