Index: include/clang/Parse/RAIIObjectsForParser.h =================================================================== --- include/clang/Parse/RAIIObjectsForParser.h +++ include/clang/Parse/RAIIObjectsForParser.h @@ -32,7 +32,8 @@ /// dependent, in that they can only be resolved with full /// information about what's being declared. They are also /// suppressed in certain contexts, like the template arguments of - /// an explicit instantiation. However, those suppression contexts + /// an explicit instantiation and an explicit/partial + /// specialization. However, those suppression contexts /// cannot necessarily be fully determined in advance; for /// example, something starting like this: /// template <> class std::vector Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -1797,6 +1797,10 @@ /// Indicates whether the InlineParams / InlineBindings storage has been used. unsigned InlineStorageUsed : 1; + /// Indicates whether the declarator is part of a + /// function/variable template-declaration or an explicit-specialization + unsigned TemplateDeclOrSpec : 1; + /// Attrs - Attributes. ParsedAttributes Attrs; @@ -1832,7 +1836,8 @@ GroupingParens(false), FunctionDefinition(FDK_Declaration), Redeclaration(false), Extension(false), ObjCIvar(false), ObjCWeakProperty(false), InlineStorageUsed(false), - Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr) {} + TemplateDeclOrSpec(false), Attrs(ds.getAttributePool().getFactory()), + AsmLabel(nullptr) {} ~Declarator() { clear(); @@ -1914,6 +1919,7 @@ Attrs.clear(); AsmLabel = nullptr; InlineStorageUsed = false; + TemplateDeclOrSpec = false; ObjCIvar = false; ObjCWeakProperty = false; CommaLoc = SourceLocation(); @@ -2415,6 +2421,9 @@ void setObjCWeakProperty(bool Val = true) { ObjCWeakProperty = Val; } bool isObjCWeakProperty() const { return ObjCWeakProperty; } + void setTemplateDeclOrSpec(bool Val = true) { TemplateDeclOrSpec = Val; } + bool isTemplateDeclOrSpec() const { return TemplateDeclOrSpec; } + void setInvalidType(bool Val = true) { InvalidType = Val; } bool isInvalidType() const { return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -4073,12 +4073,23 @@ // C++11 [temp.explicit]p12: // The usual access controls do not apply to names used to specify // explicit instantiations. - // We extend this to also cover explicit specializations. Note that - // we don't suppress if this turns out to be an elaborated type - // specifier. + // + // C++2a [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 + // + // C++2a [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 + // + // 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); // Enum definitions should not be parsed in a trailing-return-type. @@ -5262,12 +5273,17 @@ (Tok.is(tok::identifier) && (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) || Tok.is(tok::annot_cxxscope))) { + SuppressAccessChecks diagsFromDeclr(*this, D.isTemplateDeclOrSpec()); + bool EnteringContext = D.getContext() == DeclaratorContext::FileContext || D.getContext() == DeclaratorContext::MemberContext; CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext); + if (D.isTemplateDeclOrSpec()) + diagsFromDeclr.done(); + if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { // The scope spec really belongs to the direct-declarator. Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1375,15 +1375,22 @@ // The usual access checking rules do not apply to names used to specify // explicit instantiations. // - // 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++2a [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 + // + // C++2a [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 // // 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); Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -235,7 +235,10 @@ // Parse the declarator. ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); + DeclaratorInfo.setTemplateDeclOrSpec(TemplateInfo.Kind != + ParsedTemplateInfo::NonTemplate); ParseDeclarator(DeclaratorInfo); + // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. Index: test/CXX/drs/dr1xx.cpp =================================================================== --- test/CXX/drs/dr1xx.cpp +++ test/CXX/drs/dr1xx.cpp @@ -917,12 +917,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: test/SemaCXX/access.cpp =================================================================== --- test/SemaCXX/access.cpp +++ test/SemaCXX/access.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s class C { struct S; // expected-note {{previously declared 'private' here}} @@ -169,3 +169,103 @@ } void bar() { foo(); } } + +namespace P0692 { + namespace class_ { + template + class trait_type {}; + + template + class trait_nontype; + + template