Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -3195,14 +3195,14 @@ /// Represents the declaration of a typedef-name via a C++11 /// alias-declaration. -class TypeAliasDecl : public TypedefNameDecl { +class TypeAliasDecl : public TypedefNameDecl, public DeclContext { /// The template for which this is the pattern, if any. TypeAliasTemplateDecl *Template; TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo), - Template(nullptr) {} + DeclContext(TypeAlias), Template(nullptr) {} public: static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, Index: clang/include/clang/AST/DeclBase.h =================================================================== --- clang/include/clang/AST/DeclBase.h +++ clang/include/clang/AST/DeclBase.h @@ -1281,6 +1281,7 @@ /// ExportDecl /// BlockDecl /// CapturedDecl +/// TypeAliasDecl class DeclContext { /// For makeDeclVisibleInContextImpl friend class ASTDeclReader; Index: clang/include/clang/Basic/DeclNodes.td =================================================================== --- clang/include/clang/Basic/DeclNodes.td +++ clang/include/clang/Basic/DeclNodes.td @@ -22,7 +22,7 @@ def Type : DeclNode; def TypedefName : DeclNode; def Typedef : DeclNode; - def TypeAlias : DeclNode; + def TypeAlias : DeclNode, DeclContext; def ObjCTypeParam : DeclNode; def UnresolvedUsingTypename : DeclNode; def Tag : DeclNode, DeclContext; Index: clang/lib/AST/DeclBase.cpp =================================================================== --- clang/lib/AST/DeclBase.cpp +++ clang/lib/AST/DeclBase.cpp @@ -1191,6 +1191,7 @@ case Decl::OMPDeclareReduction: case Decl::OMPDeclareMapper: case Decl::RequiresExprBody: + case Decl::TypeAlias: // There is only one DeclContext for these entities. return this; Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -5657,8 +5657,24 @@ D.getContext() == DeclaratorContext::FileContext || D.getContext() == DeclaratorContext::MemberContext; CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, EnteringContext); + + { + // If this is an explicit specialization of a member of a class template, + // don't perform access checks in template parameters. + // + // See 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. + SuppressAccessChecks diagsFromTag(*this); + + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, + /*ObjectHasErrors=*/false, + EnteringContext); + } if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { 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/lib/Parse/ParseTemplate.cpp =================================================================== --- clang/lib/Parse/ParseTemplate.cpp +++ clang/lib/Parse/ParseTemplate.cpp @@ -202,11 +202,14 @@ MaybeParseCXX11Attributes(prefixAttrs); if (Tok.is(tok::kw_using)) { + ParsingDeclRAIIObject ParsingDeclRAII(*this, &DiagsFromTParams); auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, prefixAttrs); if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl()) return nullptr; - return usingDeclPtr.get().getSingleDecl(); + Decl *Decl = usingDeclPtr.get().getSingleDecl(); + ParsingDeclRAII.complete(Decl); + return Decl; } // Parse the declaration specifiers, stealing any diagnostics from Index: clang/test/CXX/drs/dr1xx.cpp =================================================================== --- clang/test/CXX/drs/dr1xx.cpp +++ clang/test/CXX/drs/dr1xx.cpp @@ -919,12 +919,12 @@ template void C::g() {} class A { - class B {}; // expected-note {{here}} + class B {}; void f(); }; template void C::f(); - template <> void C::g(); // expected-error {{private}} + template <> void C::g(); void A::f() { C cb; 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,119 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// 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 { + // expected-note@+1 4 {{declared private here}} + void func(); + + // expected-note@+1 4 {{declared private here}} + void funcOverloaded(); + + void funcOverloaded(int); + + // expected-note@+1 2 {{declared private here}} + static void staticFunc(); + + // expected-note@+1 2 {{declared private here}} + static void staticFuncOverloaded(); + + static void staticFuncOverloaded(int); + + // expected-note@+1 {{declared private here}} + class Nested {}; + + // expected-note@+1 {{declared private here}} + int field; +}; + +template class TemplateClass {}; +template <> class TemplateClass<&TestClass::func> {}; +template <> class TemplateClass<&TestClass::funcOverloaded> {}; + +// expected-error@+1 {{'func' is a private member of 'TestClass'}} +using alias1_1 = TemplateClass<&TestClass::func>; + +// expected-error@+1 {{'funcOverloaded' is a private member of 'TestClass'}} +using alias1_2 = TemplateClass<&TestClass::funcOverloaded>; + +template class TemplateClass2 { }; +template <> class TemplateClass2<&TestClass::staticFunc> {}; +template <> class TemplateClass2<&TestClass::staticFuncOverloaded> {}; + +// expected-error@+1 {{'staticFunc' is a private member of 'TestClass'}} +using alias2_1 = TemplateClass2<&TestClass::staticFunc>; + +// expected-error@+1 {{'staticFuncOverloaded' is a private member of 'TestClass'}} +using alias2_2 = TemplateClass2<&TestClass::staticFuncOverloaded>; + +template class TemplateClass3 {}; +template class TemplateClass3 {}; +template class TemplateClass3 {}; + +// expected-error@+2 {{'func' is a private member of 'TestClass'}} +template +using alias3_1 = TemplateClass3; + +// expected-error@+1 {{'func' is a private member of 'TestClass'}} +using alias3_2 = TemplateClass3; + +// expected-error@+2 {{'funcOverloaded' is a private member of 'TestClass'}} +template +using alias3_3 = TemplateClass3; + +// expected-error@+1 {{'funcOverloaded' is a private member of 'TestClass'}} +using alias3_4 = TemplateClass3; + +// expected-error@+2 {{'func' is a private member of 'TestClass'}} +template +class TemplateClass3 varTemplate3_1 {}; + +// expected-error@+2 {{'funcOverloaded' is a private member of 'TestClass'}} +template +class TemplateClass3 varTemplate3_2 {}; + +template class TemplateClass4 {}; +template class TemplateClass4 {}; +template class TemplateClass4 {}; + +// expected-error@+2 {{'staticFunc' is a private member of 'TestClass'}} +template +class TemplateClass4 varTemplate4_1 {}; + +// expected-error@+2 {{'staticFuncOverloaded' is a private member of 'TestClass'}} +template +class TemplateClass4 varTemplate4_2 {}; + +template class TemplateClass5 {}; +template<> class TemplateClass5 {}; + +template class TemplateClass6 {}; +template class TemplateClass6 {}; + +// expected-error@+2 {{'Nested' is a private member of 'TestClass'}} +template +class TemplateClass6 varTemplate6_1 {}; + +template class TemplateClass7 {}; +template <> class TemplateClass7<&TestClass::field> {}; + +template class TemplateClass8 {}; +template class TemplateClass8 {}; + +// expected-error@+2 {{'field' is a private member of 'TestClass'}} +template +class TemplateClass8 varTemplate8_1 {}; + +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,71 @@ +// 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>; + +template <> class X::Y {}; + +namespace member_spec { + + template + struct X { + struct A {}; + void f(); + enum E : int; + static int var; + }; + + class Y { + using Z = int; + }; + + template <> + struct X::A {}; + + template <> + void X::f() {} + + template <> + enum X::E : int {}; + + template <> + int X::var = 76; + +} 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