forked from OSchip/llvm-project
[clang] Implement P0692R1 from C++20 (access checking on specializations and instantiations)
This patch implements paper P0692R1 from the C++20 standard. Disable usual access checking rules to template argument names in a declaration of partial specializations, explicit instantiation or explicit specialization (C++20 13.7.5/10, 13.9.1/6). Fixes: https://llvm.org/PR37424 This patch also implements option *A* from this paper P0692R1 from the C++20 standard. This patch follows the @rsmith suggestion from D78404. Reviewed By: krisb Differential Revision: https://reviews.llvm.org/D92024
This commit is contained in:
parent
e260e10c4a
commit
638dcea010
|
@ -3091,6 +3091,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
return true;
|
||||
};
|
||||
|
||||
// Turn off usual access checking for template specializations and
|
||||
// instantiations.
|
||||
bool IsTemplateSpecOrInst =
|
||||
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
|
||||
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
|
||||
|
||||
switch (Tok.getKind()) {
|
||||
default:
|
||||
DoneWithDeclSpec:
|
||||
|
@ -3261,6 +3267,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
isConstructorDeclarator(/*Unqualified*/ false))
|
||||
goto DoneWithDeclSpec;
|
||||
|
||||
// C++20 [temp.spec] 13.9/6.
|
||||
// This disables the access checking rules for function template explicit
|
||||
// instantiation and explicit specialization:
|
||||
// - `return type`.
|
||||
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
|
||||
|
||||
ParsedType TypeRep =
|
||||
Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),
|
||||
getCurScope(), &SS, false, false, nullptr,
|
||||
|
@ -3268,6 +3280,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
/*WantNontrivialTypeSourceInfo=*/true,
|
||||
isClassTemplateDeductionContext(DSContext));
|
||||
|
||||
if (IsTemplateSpecOrInst)
|
||||
SAC.done();
|
||||
|
||||
// If the referenced identifier is not a type, then this declspec is
|
||||
// erroneous: We already checked about that it has no type specifier, and
|
||||
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
|
||||
|
@ -3377,10 +3392,24 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
// In C++, check to see if this is a scope specifier like foo::bar::, if
|
||||
// so handle it as such. This is important for ctor parsing.
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
if (TryAnnotateCXXScopeToken(EnteringContext)) {
|
||||
// C++20 [temp.spec] 13.9/6.
|
||||
// This disables the access checking rules for function template
|
||||
// explicit instantiation and explicit specialization:
|
||||
// - `return type`.
|
||||
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
|
||||
|
||||
const bool Success = TryAnnotateCXXScopeToken(EnteringContext);
|
||||
|
||||
if (IsTemplateSpecOrInst)
|
||||
SAC.done();
|
||||
|
||||
if (Success) {
|
||||
if (IsTemplateSpecOrInst)
|
||||
SAC.redelay();
|
||||
DS.SetTypeSpecError();
|
||||
goto DoneWithDeclSpec;
|
||||
}
|
||||
|
||||
if (!Tok.is(tok::identifier))
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1474,19 +1474,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
return;
|
||||
}
|
||||
|
||||
// C++03 [temp.explicit] 14.7.2/8:
|
||||
// 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.
|
||||
//
|
||||
// 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);
|
||||
// C++20 [temp.class.spec] 13.7.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.
|
||||
// C++20 [temp.spec] 13.9/6:
|
||||
// The usual access checking rules do not apply to names in a declaration
|
||||
// of an explicit instantiation or explicit specialization...
|
||||
const bool shouldDelayDiagsInTag =
|
||||
(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate);
|
||||
SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag);
|
||||
|
||||
ParsedAttributesWithRange attrs(AttrFactory);
|
||||
|
@ -1834,14 +1830,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -2018,6 +2006,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
}
|
||||
}
|
||||
|
||||
// If this is an elaborated type specifier in function template,
|
||||
// and we delayed diagnostics before,
|
||||
// just merge them into the current pool.
|
||||
if (shouldDelayDiagsInTag) {
|
||||
diagsFromTag.done();
|
||||
if (TUK == Sema::TUK_Reference &&
|
||||
TemplateInfo.Kind == ParsedTemplateInfo::Template)
|
||||
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) ||
|
||||
|
@ -2713,9 +2711,22 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
if (MalformedTypeSpec)
|
||||
DS.SetTypeSpecError();
|
||||
|
||||
// Turn off usual access checking for templates explicit specialization
|
||||
// and instantiation.
|
||||
// C++20 [temp.spec] 13.9/6.
|
||||
// This disables the access checking rules for member function template
|
||||
// explicit instantiation and explicit specialization.
|
||||
bool IsTemplateSpecOrInst =
|
||||
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
|
||||
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
|
||||
SuppressAccessChecks diagsFromTag(*this, IsTemplateSpecOrInst);
|
||||
|
||||
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DeclSpecContext::DSC_class,
|
||||
&CommonLateParsedAttrs);
|
||||
|
||||
if (IsTemplateSpecOrInst)
|
||||
diagsFromTag.done();
|
||||
|
||||
// Turn off colon protection that was set for declspec.
|
||||
X.restore();
|
||||
|
||||
|
@ -2784,6 +2795,11 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
ExprResult TrailingRequiresClause;
|
||||
bool ExpectSemi = true;
|
||||
|
||||
// C++20 [temp.spec] 13.9/6.
|
||||
// This disables the access checking rules for member function template
|
||||
// explicit instantiation and explicit specialization.
|
||||
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
|
||||
|
||||
// Parse the first declarator.
|
||||
if (ParseCXXMemberDeclaratorBeforeInitializer(
|
||||
DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) {
|
||||
|
@ -2791,6 +2807,9 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (IsTemplateSpecOrInst)
|
||||
SAC.done();
|
||||
|
||||
// Check for a member function definition.
|
||||
if (BitfieldSize.isUnset()) {
|
||||
// MSVC permits pure specifier on inline functions defined at class scope.
|
||||
|
|
|
@ -248,7 +248,27 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
|
|||
ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
|
||||
if (TemplateInfo.TemplateParams)
|
||||
DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
|
||||
|
||||
// Turn off usual access checking for template specializations and
|
||||
// instantiations.
|
||||
// C++20 [temp.spec] 13.9/6.
|
||||
// This disables the access checking rules for function template explicit
|
||||
// instantiation and explicit specialization:
|
||||
// - parameter-list;
|
||||
// - template-argument-list;
|
||||
// - noexcept-specifier;
|
||||
// - dynamic-exception-specifications (deprecated in C++11, removed since
|
||||
// C++17).
|
||||
bool IsTemplateSpecOrInst =
|
||||
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
|
||||
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
|
||||
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
|
||||
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
|
||||
if (IsTemplateSpecOrInst)
|
||||
SAC.done();
|
||||
|
||||
// Error parsing the declarator?
|
||||
if (!DeclaratorInfo.hasName()) {
|
||||
// If so, skip until the semi-colon or a }.
|
||||
|
|
|
@ -272,7 +272,7 @@ namespace test7 {
|
|||
// Return types, parameters and default arguments to friend functions.
|
||||
namespace test8 {
|
||||
class A {
|
||||
typedef int I; // expected-note 4 {{declared private here}}
|
||||
typedef int I; // expected-note 6 {{declared private here}}
|
||||
static const I x = 0; // expected-note {{implicitly declared private here}}
|
||||
friend I f(I i);
|
||||
template<typename T> friend I g(I i);
|
||||
|
@ -289,7 +289,16 @@ namespace test8 {
|
|||
template<typename T> A::I g2(A::I i) { // expected-error 2 {{is a private member of}}
|
||||
T t;
|
||||
}
|
||||
template A::I g2<A::I>(A::I i);
|
||||
template <> A::I g2<char>(A::I i) { return 0; } // OK
|
||||
template A::I g2<A::I>(A::I i); // OK
|
||||
template <> A::I g2<char>(A::I i); // OK
|
||||
template <> A::I g2<A::I *>(A::I i); // OK
|
||||
template A::I g2<unsigned>(A::I i); // OK
|
||||
template int g2<A::I **>(int i); // OK
|
||||
template A::I g2<A::I ***>(A::I i); // OK
|
||||
|
||||
template <typename T> A::I g3(A::I i) { return 0; } // expected-error 2 {{is a private member of}}
|
||||
template <> int g3<A::I>(int i); // OK
|
||||
}
|
||||
|
||||
// PR6885
|
||||
|
|
|
@ -934,12 +934,12 @@ namespace dr182 { // dr182: yes
|
|||
template <class T> void C<T>::g() {}
|
||||
|
||||
class A {
|
||||
class B {}; // expected-note {{here}}
|
||||
class B {};
|
||||
void f();
|
||||
};
|
||||
|
||||
template void C<A::B>::f();
|
||||
template <> void C<A::B>::g(); // expected-error {{private}}
|
||||
template <> void C<A::B>::g();
|
||||
|
||||
void A::f() {
|
||||
C<B> cb;
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
|
||||
|
||||
// C++20 [temp.spec] 13.9/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 : In particular, the template arguments and names used in the
|
||||
// function declarator(including parameter types, return types and exception
|
||||
// specifications) may be private types or objects that would normally not be
|
||||
// accessible. — end note]
|
||||
|
||||
class A {
|
||||
// expected-note@+1 17{{implicitly declared private here}}
|
||||
template <typename T> class B {};
|
||||
// expected-note@+1 3{{implicitly declared private here}}
|
||||
static constexpr int num1 = 42;
|
||||
|
||||
protected:
|
||||
// expected-note@+1 13{{declared protected here}}
|
||||
class C {};
|
||||
// expected-note@+1 2{{declared protected here}}
|
||||
static constexpr int num2 = 43;
|
||||
static int num4;
|
||||
|
||||
public:
|
||||
template <typename T> class D {};
|
||||
static constexpr int num3 = 44;
|
||||
};
|
||||
int A::num4 = 44;
|
||||
|
||||
class E : public A {
|
||||
|
||||
// Declarations
|
||||
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T = A::B<int>> void func1();
|
||||
template <typename T = A::C> void func2();
|
||||
template <typename T = class A::D<int>> void func3();
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> A::B<int> func4();
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> A::B<T> func5();
|
||||
template <typename T> class A::C func6();
|
||||
template <typename T> class A::D<int> func7();
|
||||
// expected-error@+1 2{{is a private member of}}
|
||||
template <typename T> void func8(class A::B<T>, int x = A::num1);
|
||||
template <typename T> void func9(A::C, A::D<T>, int = A::num3);
|
||||
|
||||
// Specializations inside class declaration
|
||||
template <> void func1<A::B<char>>() {}
|
||||
template <> void func2<class A::D<char>>() {
|
||||
} template <> void func3<class A::C>() {
|
||||
}
|
||||
template <> class A::B<int> func4<A::B<char>>() { return {}; } template <> A::B<A::D<int>> func5<A::D<int>>() {
|
||||
return {};
|
||||
}
|
||||
template <> class A::C func6<A::C>() { return {}; } template <> A::D<int> func7<char>() {
|
||||
return {};
|
||||
}
|
||||
template <> void func8<char>(class A::B<char>, int) {}
|
||||
template <> void func9<A::B<char>>(A::C, A::D<A::B<char>>, int) {}
|
||||
|
||||
// FIXME: Instantiations inside class declaration.
|
||||
// don't work correctly.
|
||||
};
|
||||
|
||||
// Definitions
|
||||
|
||||
template <typename T> void E::func1() {}
|
||||
template <typename T> void E::func2() {}
|
||||
template <typename T> void E::func3() {}
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> A::B<int> E::func4() { return {}; }
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> A::B<T> E::func5() { return {}; }
|
||||
template <typename T> A::C E::func6() { return {}; }
|
||||
template <typename T> A::D<int> E::func7() { return {}; }
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> void E::func8(A::B<T>, int) {}
|
||||
template <typename T> void E::func9(A::C, A::D<T>, int) {}
|
||||
|
||||
// Specializations
|
||||
|
||||
template <> void E::func1<A::B<int>>() {}
|
||||
template <> void E::func2<class A::C>() {}
|
||||
template <> void E::func3<class A::D<int>>() {
|
||||
} template <> class A::B<int> E::func4<A::B<int>>() {
|
||||
return {};
|
||||
} template <> A::B<A::C> E::func5<A::C>() {
|
||||
return {};
|
||||
}
|
||||
template <> class A::C E::func6<A::D<int>>() { return {}; } template <> A::D<int> E::func7<int>() {
|
||||
return {};
|
||||
}
|
||||
template <> void E::func8<int>(class A::B<int>, int) {}
|
||||
template <> void E::func9<A::C>(A::C, A::D<A::C>, int) {}
|
||||
|
||||
// Instantiations
|
||||
|
||||
template <> void E::func1<A::B<int>>();
|
||||
template <> void E::func2<class A::C>();
|
||||
template <> void E::func3<class A::D<int>>();
|
||||
template <> class A::B<int> E::func4<A::B<int>>();
|
||||
template <> A::B<A::C> E::func5<A::C>();
|
||||
template <> class A::C E::func6<A::D<int>>();
|
||||
template <> A::D<int> E::func7<int>();
|
||||
template <> void E::func8<int>(class A::B<int>, int);
|
||||
template <> void E::func9<A::C>(A::C, A::D<A::C>, int);
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// forward declarations
|
||||
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> class A::C func1();
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> A::B<T> func2();
|
||||
template <typename T> A::D<T> func3();
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> class A::B<int> func4();
|
||||
template <typename T> void func5();
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <int x = A::num1> void func6();
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <int x = A::num2> void func7();
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> void func8(int x = sizeof(A::C));
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> void func9(int x = A::num1);
|
||||
// expected-error@+2 {{is a private member of}}
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> void func10(class A::B<T>, int x = A::num2);
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> void func11(class A::C, A::D<T>, int = A::num3);
|
||||
template <typename T> void func12();
|
||||
template <int x> void func13();
|
||||
template <typename T, int x> void func14();
|
||||
template <template <typename> typename T> void func15();
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T = A::C> void func16();
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T = A::B<int>> void func17();
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> auto func18() -> A::C;
|
||||
template <typename T> T func19();
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// definitions
|
||||
|
||||
// expected-error@+1 2{{is a protected member of}}
|
||||
template <typename T> A::C func1() { A::C x; }
|
||||
// expected-error@+2 {{is a private member of}}
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> A::B<T> func2() { A::D<A::C> x; }
|
||||
template <typename T> A::D<T> func3() { A::D<int> x; }
|
||||
// expected-error@+2 2{{is a private member of}}
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> class A::B<int> func4() { A::B<A::C> x; }
|
||||
|
||||
template <typename T>
|
||||
void func5() {
|
||||
// expected-error@+2 {{is a private member of}}
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
A::B<A::D<A::C>> x;
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
A::B<int> x2;
|
||||
}
|
||||
template <typename T> void func8(int x) {}
|
||||
template <typename T> void func9(int x) {}
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> void func10(A::B<T>, int x) {}
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> void func11(A::C, A::D<T>, int) {}
|
||||
template <typename T> void func12() {}
|
||||
template <int x> void func13() {}
|
||||
template <typename T, int x> void func14() {}
|
||||
template <template <typename> typename T> void func15() {}
|
||||
template <typename T> void func16() {}
|
||||
template <typename T> void func17() {}
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> auto func18() -> A::C {
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
return A::C{};
|
||||
}
|
||||
template <typename T> T func19() {
|
||||
return T{};
|
||||
}
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// explicit specializations
|
||||
|
||||
template <> A::C func1<A::C>();
|
||||
template <> A::B<A::C> func2<A::C>();
|
||||
template <> A::D<A::C> func3<A::C>();
|
||||
template <> class A::B<int> func4<A::C>();
|
||||
template <> void func5<A::C>();
|
||||
template <> void func5<A::B<int>>();
|
||||
template <> void func5<A::D<A::C>>();
|
||||
template <> void func5<int>();
|
||||
template <> void func8<A::C>(int x);
|
||||
template <> void func9<decltype(A::num1)>(int);
|
||||
template <> void func10<A::D<int>>(A::B<A::D<int>>, int);
|
||||
template <> void func11<A::C>(A::C, A::D<A::C>, int);
|
||||
template <> void func12<class A::B<char>>() {
|
||||
} template <> void func13<A::num1>() {
|
||||
}
|
||||
template <> void func14<A::B<int>, A::num2>() {}
|
||||
template <> void func15<A::D>() {}
|
||||
template <> void func16<class A::B<char>>() {
|
||||
} template <> void func17<A::B<class A::C>>() {
|
||||
}
|
||||
template <> auto func18<int>() -> class A::C;
|
||||
template <> A::B<int> func19<class A::B<int>>();
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// explicit instantiations
|
||||
|
||||
template void func10<A::C>(A::B<A::C>, decltype(A::num1));
|
||||
template void func11<A::B<int>>(A::C, A::D<A::B<int>>, decltype(A::num2));
|
||||
template void func12<A::C>();
|
||||
template void func13<A::num2>();
|
||||
template void func13<A::num3>();
|
||||
template void func14<A::C, A::num1>();
|
||||
template void func15<A::B>();
|
||||
template void func17();
|
||||
template auto func18<char>() -> A::C;
|
||||
template class A::C func19<A::C>();
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// Other cases
|
||||
|
||||
template <int *x> class StealClass {
|
||||
friend int stealFunc() { return *x; }
|
||||
};
|
||||
|
||||
template class StealClass<&A::num4>;
|
||||
int stealFunc();
|
||||
|
||||
int stealFunc2() {
|
||||
return stealFunc();
|
||||
}
|
|
@ -0,0 +1,481 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
// C++20 [temp.class.spec] 13.7.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.
|
||||
//
|
||||
// C++20 [temp.spec] 13.9/6:
|
||||
// The usual access checking rules do not apply to names in a declaration
|
||||
// of an explicit instantiation or explicit specialization...
|
||||
|
||||
// TODO: add test cases for `enum`
|
||||
|
||||
// class for tests
|
||||
class TestClass {
|
||||
public:
|
||||
class PublicClass {};
|
||||
template <class T> 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 T> 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 T> 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 explicit instantiations
|
||||
template <typename T> class IT1 {};
|
||||
template <typename T1, typename T2> class IT2 {};
|
||||
template <int X> class IT3 {};
|
||||
template <void (TestClass::*)()> class IT4 {};
|
||||
template <void (*)()> class IT5 {};
|
||||
template <typename T> class IT6 {
|
||||
template <typename NT> class NIT1 {};
|
||||
};
|
||||
template <typename T1, typename T2> class IT7 {};
|
||||
template <void (TestClass::*)(), int X> class IT8 {};
|
||||
template <typename T, void (*)()> class IT9 {};
|
||||
|
||||
// explicit instantiations
|
||||
|
||||
// public
|
||||
template class IT1<TestClass::PublicClass>;
|
||||
template struct IT1<TestClass::TemplatePublicClass<int>>;
|
||||
template class IT1<TestClass::AliasPublicClass>;
|
||||
template struct IT2<TestClass::PublicClass, TestClass::PublicClass>;
|
||||
template class IT3<TestClass::publicStaticInt>;
|
||||
template struct IT4<&TestClass::publicFunc>;
|
||||
template class IT4<&TestClass::publicFuncOverloaded>;
|
||||
template class IT5<&TestClass::publicStaticFunc>;
|
||||
template class IT5<&TestClass::publicStaticFuncOverloaded>;
|
||||
template class IT5<&globalFunction>;
|
||||
template class IT6<TestClass::PublicClass>::template NIT1<TestClass::PublicClass>;
|
||||
template class IT7<TestClass::AliasPublicClass, TestClass::PublicClass>;
|
||||
template struct IT7<TestClass::PublicClass, TestClass::TemplatePublicClass<TestClass::PublicClass>>;
|
||||
template class IT8<&TestClass::publicFunc, TestClass::publicStaticInt>;
|
||||
template class IT8<&TestClass::publicFuncOverloaded, TestClass::publicStaticInt>;
|
||||
template class IT9<TestClass::PublicClass, &TestClass::publicStaticFunc>;
|
||||
template class IT9<TestClass::PublicClass, &TestClass::publicStaticFuncOverloaded>;
|
||||
template class IT9<TestClass::PublicClass, &globalFunction>;
|
||||
|
||||
// protected
|
||||
template class IT1<TestClass::ProtectedClass>;
|
||||
template struct IT1<TestClass::TemplateProtectedClass<int>>;
|
||||
template class IT1<TestClass::AliasProtectedClass>;
|
||||
template struct IT2<TestClass::ProtectedClass, TestClass::ProtectedClass>;
|
||||
template class IT3<TestClass::protectedStaticInt>;
|
||||
template struct IT4<&TestClass::protectedFunc>;
|
||||
template class IT4<&TestClass::protectedFuncOverloaded>;
|
||||
template class IT5<&TestClass::protectedStaticFunc>;
|
||||
template class IT5<&TestClass::protectedStaticFuncOverloaded>;
|
||||
template class IT6<TestClass::ProtectedClass>::template NIT1<TestClass::ProtectedClass>;
|
||||
template class IT7<TestClass::AliasProtectedClass, TestClass::ProtectedClass>;
|
||||
template struct IT7<TestClass::ProtectedClass, TestClass::TemplateProtectedClass<TestClass::ProtectedClass>>;
|
||||
template class IT8<&TestClass::protectedFunc, TestClass::protectedStaticInt>;
|
||||
template class IT8<&TestClass::protectedFuncOverloaded, TestClass::protectedStaticInt>;
|
||||
template class IT9<TestClass::ProtectedClass, &TestClass::protectedStaticFunc>;
|
||||
template class IT9<TestClass::ProtectedClass, &TestClass::protectedStaticFuncOverloaded>;
|
||||
template class IT9<TestClass::ProtectedClass, &globalFunction>;
|
||||
|
||||
// private
|
||||
template class IT1<TestClass::PrivateClass>;
|
||||
template struct IT1<TestClass::TemplatePrivateClass<int>>;
|
||||
template class IT1<TestClass::AliasPrivateClass>;
|
||||
template struct IT2<TestClass::PrivateClass, TestClass::PrivateClass>;
|
||||
template class IT3<TestClass::privateStaticInt>;
|
||||
template struct IT4<&TestClass::privateFunc>;
|
||||
template class IT4<&TestClass::privateFuncOverloaded>;
|
||||
template class IT5<&TestClass::privateStaticFunc>;
|
||||
template class IT5<&TestClass::privateStaticFuncOverloaded>;
|
||||
template class IT6<TestClass::PrivateClass>::template NIT1<TestClass::PrivateClass>;
|
||||
template class IT7<TestClass::AliasPrivateClass, TestClass::PrivateClass>;
|
||||
template struct IT7<TestClass::PrivateClass, TestClass::TemplatePrivateClass<TestClass::PrivateClass>>;
|
||||
template class IT8<&TestClass::privateFunc, TestClass::privateStaticInt>;
|
||||
template class IT8<&TestClass::privateFuncOverloaded, TestClass::privateStaticInt>;
|
||||
template class IT9<TestClass::PrivateClass, &TestClass::privateStaticFunc>;
|
||||
template class IT9<TestClass::PrivateClass, &TestClass::privateStaticFuncOverloaded>;
|
||||
template class IT9<TestClass::PrivateClass, &globalFunction>;
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// template declarations for full specializations
|
||||
template <typename T> class CT1 {};
|
||||
template <typename T1, typename T2> class CT2 {};
|
||||
template <int X> class CT3 {};
|
||||
template <void (TestClass::*)()> class CT4 {};
|
||||
template <void (*)()> class CT5 {};
|
||||
template <typename T> class CT6 {
|
||||
template <typename NT> class NCT1 {};
|
||||
template <typename NT> class NCT2; // forward declaration
|
||||
};
|
||||
|
||||
// full specializations
|
||||
|
||||
// public
|
||||
template <> class CT1<TestClass::PublicClass>;
|
||||
template <typename T> class CT1<TestClass::TemplatePublicClass<T>>; // not full but let it be here
|
||||
template <> struct CT1<TestClass::TemplatePublicClass<int>>;
|
||||
template <> class CT1<TestClass::AliasPublicClass>;
|
||||
template <> struct CT2<TestClass::PublicClass, TestClass::PublicClass>;
|
||||
template <> class CT3<TestClass::publicStaticInt>;
|
||||
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<TestClass::PublicClass>::NCT1<TestClass::PublicClass>;
|
||||
|
||||
template <> class CT1<TestClass::PublicClass> final {};
|
||||
template <typename T> class CT1<TestClass::TemplatePublicClass<T>> {};
|
||||
template <> class CT1<TestClass::TemplatePublicClass<int>> final {};
|
||||
template <> class CT1<TestClass::AliasPublicClass> {};
|
||||
template <> class CT2<TestClass::PublicClass, TestClass::PublicClass> final {};
|
||||
template <> class CT3<TestClass::publicStaticInt> {};
|
||||
template <> class CT4<&TestClass::publicFunc> final {};
|
||||
template <> class CT4<&TestClass::publicFuncOverloaded> {};
|
||||
template <> class CT5<&TestClass::publicStaticFunc> final {};
|
||||
template <> class CT5<&TestClass::publicStaticFuncOverloaded> {};
|
||||
template <> class CT5<&globalFunction> final {};
|
||||
template <> template <> class CT6<TestClass::PublicClass>::NCT1<TestClass::PublicClass> {};
|
||||
template <> template <typename NT> class CT6<TestClass::PublicClass>::NCT2 final {}; // declaration
|
||||
|
||||
// protected
|
||||
template <> class CT1<TestClass::ProtectedClass>;
|
||||
template <typename T> class CT1<TestClass::TemplateProtectedClass<T>>; // not full but let it be here
|
||||
template <> class CT1<TestClass::TemplateProtectedClass<int>>;
|
||||
template <> struct CT1<TestClass::AliasProtectedClass>;
|
||||
template <> class CT2<TestClass::ProtectedClass, TestClass::ProtectedClass>;
|
||||
template <> struct CT3<TestClass::protectedStaticInt>;
|
||||
template <> class CT4<&TestClass::protectedFunc>;
|
||||
template <> struct CT4<&TestClass::protectedFuncOverloaded>;
|
||||
template <> class CT5<&TestClass::protectedStaticFunc>;
|
||||
template <> class CT5<&TestClass::protectedStaticFuncOverloaded>;
|
||||
template <> template <> class CT6<TestClass::ProtectedClass>::NCT1<TestClass::ProtectedClass>;
|
||||
|
||||
template <> class CT1<TestClass::ProtectedClass> {};
|
||||
template <typename T> class CT1<TestClass::TemplateProtectedClass<T>> final {}; // not full but let it be here
|
||||
template <> class CT1<TestClass::TemplateProtectedClass<int>> {};
|
||||
template <> class CT1<TestClass::AliasProtectedClass> final {};
|
||||
template <> class CT2<TestClass::ProtectedClass, TestClass::ProtectedClass> {};
|
||||
template <> class CT3<TestClass::protectedStaticInt> final {};
|
||||
template <> class CT4<&TestClass::protectedFunc> {};
|
||||
template <> class CT4<&TestClass::protectedFuncOverloaded> final {};
|
||||
template <> class CT5<&TestClass::protectedStaticFunc> {};
|
||||
template <> class CT5<&TestClass::protectedStaticFuncOverloaded> final {};
|
||||
template <> template <> class CT6<TestClass::ProtectedClass>::NCT1<TestClass::ProtectedClass> {};
|
||||
template <> template <typename NT> class CT6<TestClass::ProtectedClass>::NCT2 final {}; // declaration
|
||||
|
||||
// private
|
||||
template <> class CT1<TestClass::PrivateClass>;
|
||||
template <typename T> class CT1<TestClass::TemplatePrivateClass<T>>; // not full but let it be here
|
||||
template <> struct CT1<TestClass::TemplatePrivateClass<int>>;
|
||||
template <> class CT1<TestClass::AliasPrivateClass>;
|
||||
template <> struct CT2<TestClass::PrivateClass, TestClass::PrivateClass>;
|
||||
template <> class CT3<TestClass::privateStaticInt>;
|
||||
template <> struct CT4<&TestClass::privateFunc>;
|
||||
template <> class CT4<&TestClass::privateFuncOverloaded>;
|
||||
template <> class CT5<&TestClass::privateStaticFunc>;
|
||||
template <> class CT5<&TestClass::privateStaticFuncOverloaded>;
|
||||
template <> template <> class CT6<TestClass::PrivateClass>::NCT1<TestClass::PrivateClass>;
|
||||
|
||||
template <> class CT1<TestClass::PrivateClass> final {};
|
||||
template <typename T> class CT1<TestClass::TemplatePrivateClass<T>> {}; // not full but let it be here
|
||||
template <> class CT1<TestClass::TemplatePrivateClass<int>> final {};
|
||||
template <> class CT1<TestClass::AliasPrivateClass> {};
|
||||
template <> class CT2<TestClass::PrivateClass, TestClass::PrivateClass> final {};
|
||||
template <> class CT3<TestClass::privateStaticInt> {};
|
||||
template <> class CT4<&TestClass::privateFunc> final {}; // PR37424
|
||||
template <> class CT4<&TestClass::privateFuncOverloaded> {}; // PR37424
|
||||
template <> class CT5<&TestClass::privateStaticFunc> final {};
|
||||
template <> class CT5<&TestClass::privateStaticFuncOverloaded> {};
|
||||
template <> template <> class CT6<TestClass::PrivateClass>::NCT1<TestClass::PrivateClass> final {};
|
||||
template <> template <typename NT> class CT6<TestClass::PrivateClass>::NCT2 {}; // declaration
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// template declarations for full specializations with parents
|
||||
class P1 {};
|
||||
template <typename T> class PCT1 {};
|
||||
template <typename T1, typename T2> class PCT2 {};
|
||||
template <int X> class PCT3 {};
|
||||
template <void (TestClass::*)()> class PCT4 {};
|
||||
template <void (*)()> class PCT5 {};
|
||||
template <typename T> class PCT6 {
|
||||
// expected-note@+1 3{{implicitly declared private here}}
|
||||
template <typename NT> class NPCT1 {};
|
||||
// expected-note@+1 {{template is declared here}}
|
||||
template <typename NT> class NPCT2; // forward declaration
|
||||
};
|
||||
|
||||
// full specializations with parents
|
||||
|
||||
// protected + public
|
||||
template <> class PCT1<TestClass::PublicClass> : P1 {};
|
||||
template <typename T> class PCT1<TestClass::TemplatePublicClass<T>> : PCT2<TestClass::PublicClass, TestClass::PublicClass> {}; // not full but let it be here
|
||||
template <> struct PCT1<TestClass::TemplatePublicClass<int>> : PCT1<TestClass::AliasPublicClass> {};
|
||||
template <> class PCT1<TestClass::AliasProtectedClass> : PCT2<TestClass::PublicClass, int> {};
|
||||
template <> struct PCT2<TestClass::ProtectedClass, TestClass::PublicClass> : PCT3<TestClass::publicStaticInt> {};
|
||||
template <> class PCT3<TestClass::protectedStaticInt> : 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<TestClass::PublicClass>::NPCT1<TestClass::PublicClass> {};
|
||||
// expected-error@+2 {{is a protected member of}}
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <> class PCT5<&globalFunction> : PCT6<TestClass::ProtectedClass>::NPCT1<int> {};
|
||||
template <> template <typename NT> class PCT6<TestClass::PublicClass>::NPCT2 : P1 {}; // declaration
|
||||
template <> template <> class PCT6<TestClass::PublicClass>::NPCT1<TestClass::ProtectedClass> : PCT6<TestClass::PublicClass>::template NPCT2<int> {};
|
||||
|
||||
// protected + private
|
||||
template <> class PCT1<TestClass::PrivateClass> : P1 {};
|
||||
// expected-error@+2 {{is a protected member of}}
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> class PCT1<TestClass::TemplatePrivateClass<T>> : PCT2<TestClass::PrivateClass, TestClass::ProtectedClass> {}; // not full but let it be here
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <> class PCT1<TestClass::TemplatePrivateClass<int>> : PCT1<TestClass::AliasProtectedClass> {};
|
||||
// expected-error@+2 {{is a protected member of}}
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <> class PCT1<TestClass::AliasPrivateClass> : PCT2<TestClass::ProtectedClass, TestClass::PrivateClass> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <> class PCT2<TestClass::PrivateClass, TestClass::PrivateClass> : PCT3<TestClass::protectedStaticInt> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <> class PCT3<TestClass::privateStaticInt> : 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<TestClass::PrivateClass>::NPCT1<TestClass::PrivateClass> : PCT6<TestClass::PrivateClass>::NPCT2<int> {};
|
||||
// expected-error@+1 3{{is a private member of}}
|
||||
template <> class PCT5<&TestClass::privateStaticFuncOverloaded> : PCT6<TestClass::PrivateClass>::NPCT1<TestClass::PrivateClass> {};
|
||||
template <> template <typename NT> class PCT6<TestClass::PrivateClass>::NPCT2 : P1 {}; // declaration
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// template declarations for partial specializations
|
||||
template <typename T1, typename T2> class CTT1 {};
|
||||
template <typename T1, typename T2, typename T3> class CTT2 {};
|
||||
template <typename T, int X> class CTT3 {};
|
||||
template <typename T, void (TestClass::*)()> class CTT4 {};
|
||||
template <typename T, void (*)()> class CTT5 {};
|
||||
template <typename T1, typename T2> class CTT6 {
|
||||
template <typename NT> class NCT1 {};
|
||||
template <typename NT> class NCT2; // forward declaration
|
||||
template <typename NT1, typename NT2> class NCT3 {};
|
||||
template <typename NT1, typename NT2> class NCT4; // forward declaration
|
||||
};
|
||||
|
||||
// partial specializations
|
||||
|
||||
// public
|
||||
template <typename T> class CTT1<T, TestClass::PublicClass> final {};
|
||||
template <typename T> class CTT1<T, TestClass::TemplatePublicClass<T>> {};
|
||||
template <typename T> struct CTT1<T, TestClass::TemplatePublicClass<int>> final {};
|
||||
template <typename T> class CTT1<T, TestClass::AliasPublicClass> {};
|
||||
template <typename T> struct CTT2<T, TestClass::PublicClass, TestClass::PublicClass> final {};
|
||||
template <typename T> struct CTT2<TestClass::PublicClass, T, TestClass::PublicClass> {};
|
||||
template <typename T> class CTT2<TestClass::PublicClass, TestClass::PublicClass, T> final {};
|
||||
template <typename T> class CTT3<T, TestClass::publicStaticInt> {};
|
||||
template <typename T> class CTT4<T, &TestClass::publicFunc> final {};
|
||||
template <typename T> class CTT4<T, &TestClass::publicFuncOverloaded> {};
|
||||
template <typename T> class CTT5<T, &TestClass::publicStaticFunc> final {};
|
||||
template <typename T> class CTT5<T, &TestClass::publicStaticFuncOverloaded> {};
|
||||
template <typename T> class CTT5<T, &globalFunction> final {};
|
||||
// expected-error@+1 {{cannot specialize a dependent template}}
|
||||
template <typename T1> template <typename T2> class CTT6<T1, TestClass::PublicClass>::template NCT1<T2 *> {};
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT1<T3 *> final {};
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT2 {}; // declaration
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT2<T3 *> final {};
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT3<T3, TestClass::PublicClass> {};
|
||||
// expected-error@+1 {{cannot specialize a dependent template}}
|
||||
template <typename T1> template <typename T2> class CTT6<T1, TestClass::PublicClass>::template NCT3<T2, TestClass::PublicClass> final {};
|
||||
template <typename T1, typename T2> template <typename T3, typename T4> class CTT6<T1, T2>::NCT4 {}; // declaration
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT4<T3, TestClass::PublicClass> final {};
|
||||
template <typename T> class CTT6<TestClass::PublicClass, T> {
|
||||
template <typename T1, typename T2> class NCT3 {};
|
||||
template <typename T1, typename T2> class NCT4;
|
||||
};
|
||||
template <typename T1> template <typename T2> class CTT6<TestClass::PublicClass, T1>::NCT3<T2, TestClass::PublicClass> {};
|
||||
template <typename T1> template <typename, typename> class CTT6<TestClass::PublicClass, T1>::NCT4 final {};
|
||||
template <typename T1> template <typename T2> class CTT6<TestClass::PublicClass, T1>::NCT4<T2, TestClass::PublicClass> {};
|
||||
|
||||
// protected
|
||||
|
||||
template <typename T> class CTT1<T, TestClass::ProtectedClass> {};
|
||||
template <typename T> class CTT1<T, TestClass::TemplateProtectedClass<T>> final {};
|
||||
template <typename T> struct CTT1<T, TestClass::TemplateProtectedClass<int>> {};
|
||||
template <typename T> class CTT1<T, TestClass::AliasProtectedClass> final {};
|
||||
template <typename T> struct CTT2<T, TestClass::ProtectedClass, TestClass::ProtectedClass> {};
|
||||
template <typename T> class CTT2<TestClass::ProtectedClass, T, TestClass::ProtectedClass> final {};
|
||||
template <typename T> struct CTT2<TestClass::ProtectedClass, TestClass::ProtectedClass, T> {};
|
||||
template <typename T> class CTT3<T, TestClass::protectedStaticInt> final {};
|
||||
template <typename T> class CTT4<T, &TestClass::protectedFunc> {};
|
||||
template <typename T> class CTT4<T, &TestClass::protectedFuncOverloaded> final {};
|
||||
template <typename T> class CTT5<T, &TestClass::protectedStaticFunc> {};
|
||||
template <typename T> class CTT5<T, &TestClass::protectedStaticFuncOverloaded> final {};
|
||||
// expected-error@+1 {{cannot specialize a dependent template}}
|
||||
template <typename T1> template <typename T2> class CTT6<T1, TestClass::ProtectedClass>::template NCT1<T2 *> {};
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT3<T3, TestClass::ProtectedClass> final {};
|
||||
// expected-error@+1 {{cannot specialize a dependent template}}
|
||||
template <typename T1> template <typename T2> class CTT6<T1, TestClass::ProtectedClass>::template NCT3<T2, TestClass::ProtectedClass> {};
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT4<T3, TestClass::ProtectedClass> final {};
|
||||
template <typename T> class CTT6<TestClass::ProtectedClass, T> {
|
||||
template <typename T1, typename T2> class NCT3 {};
|
||||
template <typename T1, typename T2> class NCT4;
|
||||
};
|
||||
template <typename T1> template <typename T2> class CTT6<TestClass::ProtectedClass, T1>::NCT3<T2, TestClass::ProtectedClass> final {};
|
||||
template <typename T1> template <typename, typename> class CTT6<TestClass::ProtectedClass, T1>::NCT4 {};
|
||||
template <typename T1> template <typename T2> class CTT6<TestClass::ProtectedClass, T1>::NCT4<T2, TestClass::ProtectedClass> final {};
|
||||
|
||||
// private
|
||||
|
||||
template <typename T> class CTT1<T, TestClass::PrivateClass> final {};
|
||||
template <typename T> class CTT1<T, TestClass::TemplatePrivateClass<T>> {};
|
||||
template <typename T> struct CTT1<T, TestClass::TemplatePrivateClass<int>> final {};
|
||||
template <typename T> class CTT1<T, TestClass::AliasPrivateClass> {};
|
||||
template <typename T> struct CTT2<T, TestClass::PrivateClass, TestClass::PrivateClass> final {};
|
||||
template <typename T> class CTT2<TestClass::PrivateClass, T, TestClass::PrivateClass> {};
|
||||
template <typename T> struct CTT2<TestClass::PrivateClass, TestClass::PrivateClass, T> final {};
|
||||
template <typename T> class CTT3<T, TestClass::privateStaticInt> {};
|
||||
template <typename T> class CTT4<T, &TestClass::privateFunc> final {};
|
||||
template <typename T> class CTT4<T, &TestClass::privateFuncOverloaded> {};
|
||||
template <typename T> class CTT5<T, &TestClass::privateStaticFunc> final {};
|
||||
template <typename T> class CTT5<T, &TestClass::privateStaticFuncOverloaded> {};
|
||||
// expected-error@+1 {{cannot specialize a dependent template}}
|
||||
template <typename T1> template <typename T2> class CTT6<T1, TestClass::PrivateClass>::template NCT1<T2 *> final {};
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT3<T3, TestClass::PrivateClass> {};
|
||||
// expected-error@+1 {{cannot specialize a dependent template}}
|
||||
template <typename T1> template <typename T2> class CTT6<T1, TestClass::PrivateClass>::template NCT3<T2, TestClass::PrivateClass> final {};
|
||||
template <typename T1, typename T2> template <typename T3> class CTT6<T1, T2>::NCT4<T3, TestClass::PrivateClass> {};
|
||||
template <typename T> class CTT6<TestClass::PrivateClass, T> {
|
||||
template <typename T1, typename T2> class NCT3 {};
|
||||
template <typename T1, typename T2> class NCT4;
|
||||
};
|
||||
template <typename T1> template <typename T2> class CTT6<TestClass::PrivateClass, T1>::NCT3<T2, TestClass::PrivateClass> {};
|
||||
template <typename T1> template <typename, typename> class CTT6<TestClass::PrivateClass, T1>::NCT4 final {};
|
||||
template <typename T1> template <typename T2> class CTT6<TestClass::PrivateClass, T1>::NCT4<T2, TestClass::PrivateClass> final {};
|
||||
|
||||
//----------------------------------------------------------//
|
||||
|
||||
// template declarations for partial specializations with parents
|
||||
template <typename T1, typename T2> class PCTT1 {};
|
||||
template <typename T1, typename T2, typename T3> class PCTT2 {};
|
||||
template <typename T, int X> class PCTT3 {};
|
||||
template <typename T, void (TestClass::*)()> class PCTT4 {};
|
||||
template <typename T, void (*)()> class PCTT5 {};
|
||||
template <typename T1, typename T2> class PCTT6 {
|
||||
template <typename NT> class NCT1 {};
|
||||
template <typename NT> class NCT2; // forward declaration
|
||||
template <typename NT1, typename NT2> class NCT3 {};
|
||||
template <typename NT1, typename NT2> class NCT4; // forward declaration
|
||||
};
|
||||
|
||||
// partial specializations with parents
|
||||
|
||||
// protected + public
|
||||
template <typename T> class PCTT1<T, TestClass::PublicClass> : P1 {};
|
||||
template <typename T> struct PCTT1<T, TestClass::TemplatePublicClass<T>> final : PCTT2<T, TestClass::PublicClass, TestClass::PublicClass> {}; // not full but let it be here
|
||||
template <typename T> class PCTT1<T, TestClass::TemplatePublicClass<int>> : PCTT1<T, TestClass::AliasPublicClass> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> class PCTT1<T, TestClass::TemplatePublicClass<TestClass::TemplateProtectedClass<T>>> final : PCTT1<T, TestClass::ProtectedClass> {};
|
||||
template <typename T> struct PCTT1<T, TestClass::AliasProtectedClass> : PCTT2<T, TestClass::PublicClass, int> {};
|
||||
template <typename T> class PCTT2<T, TestClass::ProtectedClass, TestClass::PublicClass> final : PCTT3<T, TestClass::publicStaticInt> {};
|
||||
template <typename T> class PCTT3<T, TestClass::protectedStaticInt> : PCTT4<T, &TestClass::publicFunc> {};
|
||||
template <typename T> struct PCTT4<T, &TestClass::protectedFunc> final : PCTT5<T, &TestClass::publicStaticFunc> {};
|
||||
template <typename T> class PCTT4<T, &TestClass::publicFuncOverloaded> : PCTT5<T, &TestClass::publicStaticFuncOverloaded> {};
|
||||
template <typename T> class PCTT5<T, &TestClass::protectedStaticFunc> final : PCTT5<T, &TestClass::publicStaticFuncOverloaded> {};
|
||||
template <typename T> class PCTT5<T, &TestClass::protectedStaticFuncOverloaded> : PCTT6<T, TestClass::PublicClass>::template NCT1<TestClass::PublicClass> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> class PCTT5<T, &globalFunction> : PCTT6<T, TestClass::ProtectedClass>::template NCT1<int> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T1, typename T2> template <typename T3> class PCTT6<T1, T2>::NCT2 final : PCTT4<T1, &TestClass::protectedFunc> {}; // declaration
|
||||
template <typename T1, typename T2> template <typename T3> class PCTT6<T1, T2>::NCT2<T3 *> : P1 {};
|
||||
// expected-error@+2 {{cannot specialize a dependent template}}
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> template <typename NT> class PCTT6<T, TestClass::ProtectedClass>::template NCT1<NT *> : PCTT6<T, TestClass::ProtectedClass>::template NCT2<int> {};
|
||||
|
||||
// protected + private
|
||||
template <typename T> class PCTT1<T, TestClass::PrivateClass> : P1 {};
|
||||
// expected-error@+2 {{is a protected member of}}
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> struct PCTT1<T, TestClass::TemplatePrivateClass<T>> final : PCTT2<T, TestClass::PrivateClass, TestClass::ProtectedClass> {}; // not full but let it be here
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> class PCTT1<T, TestClass::TemplatePrivateClass<int>> : PCTT1<T, TestClass::AliasProtectedClass> {};
|
||||
// expected-error@+2 {{is a protected member of}}
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> struct PCTT1<T, TestClass::AliasPrivateClass> final : PCTT2<T, TestClass::ProtectedClass, TestClass::PrivateClass> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> class PCTT2<T, TestClass::PrivateClass, TestClass::TemplatePrivateClass<T>> : PCTT3<T, TestClass::protectedStaticInt> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> class PCTT3<T, TestClass::privateStaticInt> final : PCTT4<T, &TestClass::protectedFunc> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> struct PCTT4<T, &TestClass::privateFunc> : PCTT5<T, &TestClass::protectedStaticFunc> {};
|
||||
// expected-error@+1 {{is a protected member of}}
|
||||
template <typename T> class PCTT4<T, &TestClass::privateFuncOverloaded> final : PCTT5<T, &TestClass::protectedStaticFuncOverloaded> {};
|
||||
template <typename T> class PCTT5<T, &TestClass::privateStaticFunc> : P1 {};
|
||||
// expected-error@+2 {{cannot specialize a dependent template}}
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> class PCTT6<T, TestClass::PrivateClass>::template PCTT1<TestClass::PrivateClass> : PCTT6<T, TestClass::PrivateClass>::template NCT2<int> {};
|
||||
// expected-error@+1 {{is a private member of}}
|
||||
template <typename T> class PCTT5<T, &TestClass::privateStaticFuncOverloaded> final : PCTT6<T, T>::template NCT1<TestClass::PrivateClass> {};
|
||||
template <typename T> class PCTT6<TestClass::PrivateClass, T> {
|
||||
template <typename T1, typename T2> class NCT3 final {};
|
||||
template <typename T1, typename T2> class NCT4;
|
||||
};
|
||||
template <typename T1> template <typename, typename> class PCTT6<TestClass::PrivateClass, T1>::NCT4 final {};
|
||||
// expected-error@+1 2{{is a private member of}}
|
||||
template <typename T1> template <typename T2> struct PCTT6<TestClass::PrivateClass, T1>::template NCT3<T2, TestClass::TemplatePrivateClass<TestClass::TemplateProtectedClass<TestClass::PublicClass>>> : PCTT6<TestClass::PrivateClass, T1>::NCT4<T2, TestClass::TemplatePrivateClass<int>> {};
|
|
@ -1,19 +0,0 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
class X {
|
||||
template <typename T> 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<A::B>;
|
||||
|
||||
// As an extension, this rule is applied to explicit specializations as well.
|
||||
template <> class X::Y<A::C> {};
|
|
@ -43,7 +43,14 @@ namespace test2 {
|
|||
Temp(int x) {}
|
||||
};
|
||||
|
||||
template <> class Temp<A::Private> Temp<int>::make() { // expected-error {{'Private' is a private member of 'test2::A'}}
|
||||
template <> class Temp<A::Private> Temp<int>::make() {
|
||||
return Temp<A::Public>(0);
|
||||
}
|
||||
|
||||
template <>
|
||||
class Temp<char> {
|
||||
static Temp<A::Private> make() { // expected-error {{is a private member}}
|
||||
return Temp<A::Public>(0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue