diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2846,7 +2846,8 @@ void ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface, SourceLocation FriendLoc); - bool isCXX11FinalKeyword() const; + bool isCXX11FinalKeyword(const Token &Tok) const; + bool isCXX11FinalKeyword() const { return isCXX11FinalKeyword(Tok); } /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// enter a new C++ declarator scope and exit it when the function is diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2998,7 +2998,7 @@ // the token as an identifier. if (getLangOpts().MSVCCompat && Tok.is(tok::kw__Atomic) && DS.getStorageClassSpec() == clang::DeclSpec::SCS_typedef && - !DS.hasTypeSpecifier() && GetLookAheadToken(1).is(tok::less)) + !DS.hasTypeSpecifier() && NextToken().is(tok::less)) Tok.setKind(tok::identifier); SourceLocation Loc = Tok.getLocation(); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1770,14 +1770,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) { @@ -1950,6 +1942,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) || @@ -2292,8 +2292,8 @@ /// isCXX11FinalKeyword - Determine whether the next token is a C++11 /// 'final' or Microsoft 'sealed' contextual keyword. -bool Parser::isCXX11FinalKeyword() const { - VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(); +bool Parser::isCXX11FinalKeyword(const Token &Tok) const { + VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok); return Specifier == VirtSpecifiers::VS_Final || Specifier == VirtSpecifiers::VS_GNU_Final || Specifier == VirtSpecifiers::VS_Sealed; diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -167,6 +167,52 @@ LastParamListWasEmpty), DeclEnd); + // Check whether it is a partial specialization. + + // TODO. This can produce wrong detection in case of a later class + // declaration. Example: + // // forward declaration of a nested class C2 + // template C1 {template C2;}; + // //later declaration of a class C2 End example. + // template template C1::C2 {}; + + // Keyword `using` means that it's an alias declaration. + if (!isSpecialization && !ParamLists.empty() && Tok.isNot(tok::kw_using) && + Tok.isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union)) { + // Next sequences of tokens can surely identify a partial specialization: + // `>::` in `class A::C{};` + // `>{` in `class A::B{};` + // `> final` in `class A::B final {};` + // `>;` in `class A::B;` + // `> :` in `class A::B : D {};` + // `>>::` in `class A>::C{};` + // `>>{` in `class A::B>{};` + // `>> final` in `class A::B> final {};` + // `>>;` in `class A::B>;` + // `>> :` in `class A::B> : E {};` + // `>>>::` in `class A>>::C{};` + // `>>>{` in `class A::B>>{};` + // `>>> final` in `class A::B>> final {};` + // `>>>;` in `class A::B>>;` + // `>>> :` in `class A::B>> : F {};` + int TokIdx = 0; + Token NextTok; + Token NextNextTok = GetLookAheadToken(TokIdx++); + // Look ahead until `{` or `;`. + while (!NextNextTok.isOneOf(tok::l_brace, tok::semi)) { + NextTok = NextNextTok; + NextNextTok = GetLookAheadToken(TokIdx++); + + if (NextTok.isOneOf(tok::greater, tok::greatergreater, + tok::greatergreatergreater) && + (NextNextTok.isOneOf(tok::coloncolon, tok::l_brace, tok::semi, + tok::colon) || + (NextNextTok.is(tok::identifier) && + isCXX11FinalKeyword(NextNextTok)))) + isSpecialization = true; + } + } + return ParseSingleDeclarationAfterTemplate( Context, ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), @@ -245,6 +291,11 @@ else DS.takeAttributesFrom(prefixAttrs); + const bool NeedSuppressAccessChecks = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + SuppressAccessChecks SuppressAccessGuard(*this, NeedSuppressAccessChecks); + // Parse the declarator. ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); if (TemplateInfo.TemplateParams) @@ -259,6 +310,9 @@ return nullptr; } + if (NeedSuppressAccessChecks) + SuppressAccessGuard.done(); + llvm::TimeTraceScope TimeScope("ParseTemplate", [&]() { return std::string(DeclaratorInfo.getIdentifier() != nullptr ? DeclaratorInfo.getIdentifier()->getName() diff --git a/clang/test/CXX/drs/dr1xx.cpp b/clang/test/CXX/drs/dr1xx.cpp --- a/clang/test/CXX/drs/dr1xx.cpp +++ b/clang/test/CXX/drs/dr1xx.cpp @@ -934,12 +934,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; diff --git a/clang/test/CXX/temp/temp.spec/func.spec.cpp b/clang/test/CXX/temp/temp.spec/func.spec.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CXX/temp/temp.spec/func.spec.cpp @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// 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. + +class A { + // expected-note@+1 14{{implicitly declared private here}} + template class B {}; + // expected-note@+1 {{implicitly declared private here}} + static constexpr int num = 42; + +protected: + // expected-note@+1 9{{declared protected here}} + class C {}; + // expected-note@+1 {{declared protected here}} + static constexpr int num2 = 42; + +public: + template class D {}; +}; + +class E : public A { + template A::C func1(); + // expected-error@+1 {{is a private member of}} + template A::B func2(); + template A::D func3(); + // expected-error@+1 {{is a private member of}} + template class A::B func4(); + template void func5(); + + template <> A::C func1(); + // expected-error@+1 {{is a private member of}} + template <> A::B func2(); + template <> A::D func3(); + // expected-error@+1 {{is a private member of}} + template <> class A::B func4(); + template <> void func5(); + // expected-error@+1 {{is a private member of}} + template <> void func5>(); + template <> void func5>(); + template <> void func5(); +}; + +// expected-error@+1 {{is a protected member of}} +template A::C func1(); +// expected-error@+1 {{is a private member of}} +template A::B func2(); +template A::D func3(); +// expected-error@+1 {{is a private member of}} +template class A::B func4(); +template void func5(); +// expected-error@+1 {{is a private member of}} +template void func6(); +// expected-error@+1 {{is a protected member of}} +template void func7(); + +// expected-error@+1 2{{is a protected member of}} +template A::C func1() { A::C x; } +// expected-error@+2 {{is a private member of}} +// expected-error@+1 {{is a protected member of}} +template A::B func2() { A::D x; } +template A::D func3() { A::D x; } +// expected-error@+2 2{{is a private member of}} +// expected-error@+1 {{is a protected member of}} +template class A::B func4() { A::B x; } template +void func5() { + // expected-error@+2 {{is a private member of}} + // expected-error@+1 {{is a protected member of}} + A::B> x; + // expected-error@+1 {{is a private member of}} + A::B x2; +} + +// expected-error@+1 {{is a protected member of}} +template <> A::C func1(); +// expected-error@+2 {{is a private member of}} +// expected-error@+1 {{is a protected member of}} +template <> A::B func2(); +// expected-error@+1 {{is a protected member of}} +template <> A::D func3(); +// expected-error@+1 {{is a private member of}} +template <> class A::B func4(); +template <> void func5(); +template <> void func5>(); +template <> void func5>(); +template <> void func5(); \ No newline at end of file diff --git a/clang/test/CXX/temp/temp.spec/part.spec.cpp b/clang/test/CXX/temp/temp.spec/part.spec.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CXX/temp/temp.spec/part.spec.cpp @@ -0,0 +1,565 @@ +// 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. + +// TODO: add test cases for `enum` + +// class for tests +class TestClass { +public: + class PublicClass {}; + template class TemplatePublicClass {}; + + using AliasPublicClass = unsigned char; + + void publicFunc(); + void publicFuncOverloaded(); + void publicFuncOverloaded(int); + + static void publicStaticFunc(); + static void publicStaticFuncOverloaded(); + static void publicStaticFuncOverloaded(int); + + static constexpr int publicStaticInt = 42; + +protected: + // expected-note@+1 8{{declared protected here}} + class ProtectedClass {}; + template class TemplateProtectedClass {}; + + // expected-note@+1 2{{declared protected here}} + using AliasProtectedClass = const char; + + // expected-note@+1 3{{declared protected here}} + void protectedFunc(); + void protectedFuncOverloaded(); + void protectedFuncOverloaded(int); + + // expected-note@+1 2{{declared protected here}} + static void protectedStaticFunc(); + // expected-note@+1 2{{declared protected here}} + static void protectedStaticFuncOverloaded(); + static void protectedStaticFuncOverloaded(int); + + // expected-note@+1 2{{declared protected here}} + static constexpr int protectedStaticInt = 43; + +private: + // expected-note@+1 10{{declared private here}} + class PrivateClass {}; + // expected-note@+1 {{declared private here}} + template class TemplatePrivateClass {}; + + using AliasPrivateClass = char *; + + void privateFunc(); + void privateFuncOverloaded(); + void privateFuncOverloaded(int); + + static void privateStaticFunc(); + static void privateStaticFuncOverloaded(); + static void privateStaticFuncOverloaded(int); + + static constexpr int privateStaticInt = 44; +}; + +void globalFunction() {} + +//----------------------------------------------------------// + +// template declarations for full specializations +template class CT1 {}; +template class CT2 {}; +template class CT3 {}; +template class CT4 {}; +template class CT5 {}; +template class CT6 { + template class NCT1 {}; + template class NCT2; // forward declaration +}; + +// full specializations + +// public +template <> class CT1; +template class CT1>; // not full but let it be here +template <> struct CT1>; +template <> class CT1; +template <> struct CT2; +template <> class CT3; +template <> struct CT4<&TestClass::publicFunc>; +template <> class CT4<&TestClass::publicFuncOverloaded>; +template <> struct CT5<&TestClass::publicStaticFunc>; +template <> class CT5<&TestClass::publicStaticFuncOverloaded>; +template <> class CT5<&globalFunction>; +template <> template <> class CT6::NCT1; + +template <> class CT1 {}; +template class CT1> {}; +template <> class CT1> {}; +template <> class CT1 {}; +template <> class CT2 {}; +template <> class CT3 {}; +template <> class CT4<&TestClass::publicFunc> {}; +template <> class CT4<&TestClass::publicFuncOverloaded> {}; +template <> class CT5<&TestClass::publicStaticFunc> {}; +template <> class CT5<&TestClass::publicStaticFuncOverloaded> {}; +template <> class CT5<&globalFunction> {}; +template <> template <> class CT6::NCT1 {}; +template <> template class CT6::NCT2 {}; // declaration + +// protected +template <> class CT1; +template class CT1>; // not full but let it be here +template <> class CT1>; +template <> struct CT1; +template <> class CT2; +template <> struct CT3; +template <> class CT4<&TestClass::protectedFunc>; +template <> struct CT4<&TestClass::protectedFuncOverloaded>; +template <> class CT5<&TestClass::protectedStaticFunc>; +template <> class CT5<&TestClass::protectedStaticFuncOverloaded>; +template <> template <> class CT6::NCT1; + +template <> class CT1 {}; +template class CT1> {}; // not full but let it be here +template <> class CT1> {}; +template <> class CT1 {}; +template <> class CT2 {}; +template <> class CT3 {}; +template <> class CT4<&TestClass::protectedFunc> {}; +template <> class CT4<&TestClass::protectedFuncOverloaded> {}; +template <> class CT5<&TestClass::protectedStaticFunc> {}; +template <> class CT5<&TestClass::protectedStaticFuncOverloaded> {}; +template <> template <> class CT6::NCT1 {}; +template <> template class CT6::NCT2 {}; // declaration + +// private +template <> class CT1; +template class CT1>; // not full but let it be here +template <> struct CT1>; +template <> class CT1; +template <> struct CT2; +template <> class CT3; +template <> struct CT4<&TestClass::privateFunc>; +template <> class CT4<&TestClass::privateFuncOverloaded>; +template <> class CT5<&TestClass::privateStaticFunc>; +template <> class CT5<&TestClass::privateStaticFuncOverloaded>; +template <> template <> class CT6::NCT1; + +template <> class CT1 {}; +template class CT1> {}; // not full but let it be here +template <> class CT1> {}; +template <> class CT1 {}; +template <> class CT2 {}; +template <> class CT3 {}; +template <> class CT4<&TestClass::privateFunc> {}; // PR37424 +template <> class CT4<&TestClass::privateFuncOverloaded> {}; // PR37424 +template <> class CT5<&TestClass::privateStaticFunc> {}; +template <> class CT5<&TestClass::privateStaticFuncOverloaded> {}; +template <> template <> class CT6::NCT1 {}; +template <> template class CT6::NCT2 {}; // declaration + +//----------------------------------------------------------// + +// template declarations for full final specializations +template class FCT1 {}; +template class FCT2 {}; +template class FCT3 {}; +template class FCT4 {}; +template class FCT5 {}; +template class FCT6 { + template class NCT1 {}; + template class NCT2; // forward declaration +}; + +// full final specializations + +// public +template <> class FCT1 final {}; +template class FCT1> final {}; // not full but let it be here +template <> struct FCT1> final {}; +template <> class FCT1 final {}; +template <> struct FCT2 final {}; +template <> class FCT3 final {}; +template <> struct FCT4<&TestClass::publicFunc> final {}; +template <> class FCT4<&TestClass::publicFuncOverloaded> final {}; +template <> class FCT5<&TestClass::publicStaticFunc> final {}; +template <> class FCT5<&TestClass::publicStaticFuncOverloaded> final {}; +template <> class FCT5<&globalFunction> final {}; +template <> template <> class FCT6::NCT1 final {}; +template <> template class FCT6::NCT2 final {}; + +// protected +template <> class FCT1 final {}; +template class FCT1> final {}; // not full but let it be here +template <> struct FCT1> final {}; +template <> class FCT1 final {}; +template <> struct FCT2 final {}; +template <> class FCT3 final {}; +template <> struct FCT4<&TestClass::protectedFunc> final {}; +template <> class FCT4<&TestClass::protectedFuncOverloaded> final {}; +template <> class FCT5<&TestClass::protectedStaticFunc> final {}; +template <> class FCT5<&TestClass::protectedStaticFuncOverloaded> final {}; +template <> template <> class FCT6::NCT1 final {}; +template <> template class FCT6::NCT2 final {}; + +// private +template <> class FCT1 final {}; +template class FCT1> final {}; // not full but let it be here +template <> struct FCT1> final {}; +template <> class FCT1 final {}; +template <> struct FCT2 final {}; +template <> class FCT3 final {}; +template <> struct FCT4<&TestClass::privateFunc> final {}; +template <> class FCT4<&TestClass::privateFuncOverloaded> final {}; +template <> class FCT5<&TestClass::privateStaticFunc> final {}; +template <> class FCT5<&TestClass::privateStaticFuncOverloaded> final {}; +template <> template <> class FCT6::NCT1 final {}; +template <> template class FCT6::NCT2 final {}; + +//----------------------------------------------------------// + +// template declarations for full specializations with parents +class P1 {}; +template class PCT1 {}; +template class PCT2 {}; +template class PCT3 {}; +template class PCT4 {}; +template class PCT5 {}; +template class PCT6 { + // expected-note@+1 3{{implicitly declared private here}} + template class NPCT1 {}; + // expected-note@+1 {{template is declared here}} + template class NPCT2; // forward declaration +}; + +// full specializations with parents + +// protected + public +template <> class PCT1 : P1 {}; +template class PCT1> : PCT2 {}; // not full but let it be here +template <> struct PCT1> : PCT1 {}; +template <> class PCT1 : PCT2 {}; +template <> struct PCT2 : PCT3 {}; +template <> class PCT3 : PCT4<&TestClass::publicFunc> {}; +template <> struct PCT4<&TestClass::protectedFunc> : PCT5<&TestClass::publicStaticFunc> {}; +template <> class PCT4<&TestClass::publicFuncOverloaded> : PCT5<&TestClass::publicStaticFuncOverloaded> {}; +template <> class PCT5<&TestClass::protectedStaticFunc> : PCT5<&TestClass::publicStaticFuncOverloaded> {}; +// expected-error@+1 {{is a private member of}} +template <> class PCT5<&TestClass::protectedStaticFuncOverloaded> : PCT6::NPCT1 {}; +// expected-error@+2 {{is a protected member of}} +// expected-error@+1 {{is a private member of}} +template <> class PCT5<&globalFunction> : PCT6::NPCT1 {}; +template <> template class PCT6::NPCT2 : P1 {}; // declaration +template <> template <> class PCT6::NPCT1 : PCT6::template NPCT2 {}; + +// protected + private +template <> class PCT1 : P1 {}; +// expected-error@+2 {{is a protected member of}} +// expected-error@+1 {{is a private member of}} +template class PCT1> : PCT2 {}; // not full but let it be here +// expected-error@+1 {{is a protected member of}} +template <> class PCT1> : PCT1 {}; +// expected-error@+2 {{is a protected member of}} +// expected-error@+1 {{is a private member of}} +template <> class PCT1 : PCT2 {}; +// expected-error@+1 {{is a protected member of}} +template <> class PCT2 : PCT3 {}; +// expected-error@+1 {{is a protected member of}} +template <> class PCT3 : PCT4<&TestClass::protectedFunc> {}; +// expected-error@+1 {{is a protected member of}} +template <> class PCT4<&TestClass::privateFunc> : PCT5<&TestClass::protectedStaticFunc> {}; +// expected-error@+1 {{is a protected member of}} +template <> class PCT4<&TestClass::privateFuncOverloaded> : PCT5<&TestClass::protectedStaticFuncOverloaded> {}; +template <> class PCT5<&TestClass::privateStaticFunc> : P1 {}; +// expected-error@+2 {{implicit instantiation of undefined template}} +// expected-error@+1 {{is a private member of}} +template <> template <> class PCT6::NPCT1 : PCT6::NPCT2 {}; +// expected-error@+1 3{{is a private member of}} +template <> class PCT5<&TestClass::privateStaticFuncOverloaded> : PCT6::NPCT1 {}; +template <> template class PCT6::NPCT2 : P1 {}; // declaration + +//----------------------------------------------------------// + +// template declarations for partial specializations +template class CTT1 {}; +template class CTT2 {}; +template class CTT3 {}; +template class CTT4 {}; +template class CTT5 {}; +template class CTT6 { + template class NCT1 {}; + template class NCT2; // forward declaration + template class NCT3 {}; + template class NCT4; // forward declaration +}; + +// partial specializations + +// public +template class CTT1 {}; +template class CTT1> {}; +template struct CTT1> {}; +template class CTT1 {}; +template struct CTT2 {}; +template struct CTT2 {}; +template class CTT2 {}; +template class CTT3 {}; +template class CTT4 {}; +template class CTT4 {}; +template class CTT5 {}; +template class CTT5 {}; +template class CTT5 {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class CTT6::template NCT1 {}; +template template class CTT6::NCT1 {}; +template template class CTT6::NCT2 {}; // declaration +template template class CTT6::NCT2 {}; +template template class CTT6::NCT3 {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class CTT6::template NCT3 {}; +template template class CTT6::NCT4 {}; // declaration +template template class CTT6::NCT4 {}; +template class CTT6 { + template class NCT3 {}; + template class NCT4; +}; +template template class CTT6::NCT3 {}; +template template class CTT6::NCT4 {}; +template template class CTT6::NCT4 {}; + +// protected + +template class CTT1 {}; +template class CTT1> {}; +template struct CTT1> {}; +template class CTT1 {}; +template struct CTT2 {}; +template class CTT2 {}; +template struct CTT2 {}; +template class CTT3 {}; +template class CTT4 {}; +template class CTT4 {}; +template class CTT5 {}; +template class CTT5 {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class CTT6::template NCT1 {}; +template template class CTT6::NCT3 {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class CTT6::template NCT3 {}; +template template class CTT6::NCT4 {}; +template class CTT6 { + template class NCT3 {}; + template class NCT4; +}; +template template class CTT6::NCT3 {}; +template template class CTT6::NCT4 {}; +template template class CTT6::NCT4 {}; + +// private + +template class CTT1 {}; +template class CTT1> {}; +template struct CTT1> {}; +template class CTT1 {}; +template struct CTT2 {}; +template class CTT2 {}; +template struct CTT2 {}; +template class CTT3 {}; +template class CTT4 {}; +template class CTT4 {}; +template class CTT5 {}; +template class CTT5 {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class CTT6::template NCT1 {}; +template template class CTT6::NCT3 {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class CTT6::template NCT3 {}; +template template class CTT6::NCT4 {}; +template class CTT6 { + template class NCT3 {}; + template class NCT4; +}; +template template class CTT6::NCT3 {}; +template template class CTT6::NCT4 {}; +template template class CTT6::NCT4 {}; + +//----------------------------------------------------------// + +// template declarations for final partial specializations +template class FCTT1 {}; +template class FCTT2 {}; +template class FCTT3 {}; +template class FCTT4 {}; +template class FCTT5 {}; +template class FCTT6 { + template class NCT1 {}; + template class NCT2; // forward declaration + template class NCT3 {}; + template class NCT4; // forward declaration +}; + +// partial final specializations + +// public +template class FCTT1 final {}; +template class FCTT1> final {}; +template struct FCTT1> final {}; +template class FCTT1 final {}; +template struct FCTT2 final {}; +template class FCTT2 final {}; +template struct FCTT2 final {}; +template class FCTT3 final {}; +template class FCTT4 final {}; +template class FCTT4 final {}; +template class FCTT5 final {}; +template class FCTT5 final {}; +template class FCTT5 final {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class FCTT6::template NCT1 final {}; +template template class FCTT6::NCT1 final {}; +template template class FCTT6::NCT2 final {}; // declaration +template template class FCTT6::NCT2 final {}; +template template class FCTT6::NCT3 final {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class FCTT6::template NCT3 final {}; +template template class FCTT6::NCT4 final {}; // declaration +template template class FCTT6::NCT4 final {}; +template class FCTT6 { + template class NCT3 final {}; + template class NCT4; +}; +template template class FCTT6::NCT3 final {}; +template template class FCTT6::NCT4 final {}; +template template class FCTT6::NCT4 final {}; + +// protected + +template class FCTT1 final {}; +template class FCTT1> final {}; +template struct FCTT1> final {}; +template class FCTT1 final {}; +template struct FCTT2 final {}; +template class FCTT2 final {}; +template struct FCTT2 final {}; +template class FCTT3 final {}; +template class FCTT4 final {}; +template class FCTT4 final {}; +template class FCTT5 final {}; +template class FCTT5 final {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class FCTT6::template NCT1 final {}; +template template class FCTT6::NCT3 final {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class FCTT6::template NCT3 final {}; +template template class FCTT6::NCT4 final {}; +template class FCTT6 { + template class NCT3 final {}; + template class NCT4; +}; +template template class FCTT6::NCT3 final {}; +template template class FCTT6::NCT4 final {}; +template template class FCTT6::NCT4 final {}; + +// private + +template class FCTT1 final {}; +template class FCTT1> final {}; +template struct FCTT1> final {}; +template class FCTT1 final {}; +template struct FCTT2 final {}; +template class FCTT2 final {}; +template struct FCTT2 final {}; +template class FCTT3 final {}; +template class FCTT4 final {}; +template class FCTT4 final {}; +template class FCTT5 final {}; +template class FCTT5 final {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class FCTT6::template NCT1 final {}; +template template class FCTT6::NCT3 final {}; +// expected-error@+1 {{cannot specialize a dependent template}} +template template class FCTT6::template NCT3 final {}; +template template class FCTT6::NCT4 final {}; +template class FCTT6 { + template class NCT3 final {}; + template class NCT4; +}; +template template class FCTT6::NCT3 final {}; +template template class FCTT6::NCT4 final {}; +template template class FCTT6::NCT4 final {}; + +//----------------------------------------------------------// + +// template declarations for partial specializations with parents +template class PCTT1 {}; +template class PCTT2 {}; +template class PCTT3 {}; +template class PCTT4 {}; +template class PCTT5 {}; +template class PCTT6 { + template class NCT1 {}; + template class NCT2; // forward declaration + template class NCT3 {}; + template class NCT4; // forward declaration +}; + +// partial specializations with parents + +// protected + public +template class PCTT1 : P1 {}; +template struct PCTT1> : PCTT2 {}; // not full but let it be here +template class PCTT1> : PCTT1 {}; +// expected-error@+1 {{is a protected member of}} +template class PCTT1>> : PCTT1 {}; +template struct PCTT1 : PCTT2 {}; +template class PCTT2 : PCTT3 {}; +template class PCTT3 : PCTT4 {}; +template struct PCTT4 : PCTT5 {}; +template class PCTT4 : PCTT5 {}; +template class PCTT5 : PCTT5 {}; +template class PCTT5 : PCTT6::template NCT1 {}; +// expected-error@+1 {{is a protected member of}} +template class PCTT5 : PCTT6::template NCT1 {}; +// expected-error@+1 {{is a protected member of}} +template template class PCTT6::NCT2 : PCTT4 {}; // declaration +template template class PCTT6::NCT2 : P1 {}; +// expected-error@+2 {{cannot specialize a dependent template}} +// expected-error@+1 {{is a protected member of}} +template template class PCTT6::template NCT1 : PCTT6::template NCT2 {}; + +// protected + private +template class PCTT1 : P1 {}; +// expected-error@+2 {{is a protected member of}} +// expected-error@+1 {{is a private member of}} +template struct PCTT1> : PCTT2 {}; // not full but let it be here +// expected-error@+1 {{is a protected member of}} +template class PCTT1> : PCTT1 {}; +// expected-error@+2 {{is a protected member of}} +// expected-error@+1 {{is a private member of}} +template struct PCTT1 : PCTT2 {}; +// expected-error@+1 {{is a protected member of}} +template class PCTT2> : PCTT3 {}; +// expected-error@+1 {{is a protected member of}} +template class PCTT3 : PCTT4 {}; +// expected-error@+1 {{is a protected member of}} +template struct PCTT4 : PCTT5 {}; +// expected-error@+1 {{is a protected member of}} +template class PCTT4 : PCTT5 {}; +template class PCTT5 : P1 {}; +// expected-error@+2 {{cannot specialize a dependent template}} +// expected-error@+1 {{is a private member of}} +template class PCTT6::template PCTT1 : PCTT6::template NCT2 {}; +// expected-error@+1 {{is a private member of}} +template class PCTT5 : PCTT6::template NCT1 {}; +template class PCTT6 { + template class NCT3 final {}; + template class NCT4; +}; +template template class PCTT6::NCT4 {}; +// expected-error@+1 2{{is a private member of}} +template template struct PCTT6::template NCT3>> : PCTT6::NCT4> {};