broadwaylamb updated this revision to Diff 258555.
broadwaylamb added a comment.
- Add more tests
- Allow class template member explicit specializations
- Inherit TypeAliasDecl from DeclContext (this is needed so that we could
perform access checks when parsing 'using' declaration templates)
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D78404/new/
https://reviews.llvm.org/D78404
Files:
clang/include/clang/AST/Decl.h
clang/include/clang/AST/DeclBase.h
clang/include/clang/Basic/DeclNodes.td
clang/lib/AST/DeclBase.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseTemplate.cpp
clang/test/CXX/drs/dr1xx.cpp
clang/test/CXX/temp/temp.decls/temp.class.spec/p10.cpp
clang/test/CXX/temp/temp.spec/p6.cpp
clang/test/CXX/temp/temp.spec/temp.explicit/p11.cpp
clang/www/cxx_status.html
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -966,7 +966,7 @@
<tr>
<td>Access checking on specializations</td>
<td><a href="https://wg21.link/p0692r1">P0692R1</a></td>
- <td class="partial" align="center">Partial</td>
+ <td class="unreleased" align="center">Clang 11</td>
</tr>
<tr>
<td>Default constructible and assignable stateless lambdas</td>
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 <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> {};
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 <typename T> 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<A::B>;
+
+template <void (A::*)()> class D {};
+template class D<&A::func>;
+template class D<&A::funcOverloaded>;
+
+template <void (*)()> class E { };
+template class E<&A::staticFunc>;
+template class E<&A::staticFuncOverloaded>;
+
+template <int A::*> class G {};
+template class G<&A::field>;
+
+template <> class X::Y<A::C> {};
+
+namespace member_spec {
+
+ template <typename T>
+ struct X {
+ struct A {};
+ void f();
+ enum E : int;
+ static int var;
+ };
+
+ class Y {
+ using Z = int;
+ };
+
+ template <>
+ struct X<Y::Z>::A {};
+
+ template <>
+ void X<Y::Z>::f() {}
+
+ template <>
+ enum X<Y::Z>::E : int {};
+
+ template <>
+ int X<Y::Z>::var = 76;
+
+}
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 <void (TestClass::*)()> 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 <void (*)()> 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<typename T, void (TestClass::*)()> class TemplateClass3 {};
+template<typename T> class TemplateClass3<T, &TestClass::func> {};
+template<typename T> class TemplateClass3<T, &TestClass::funcOverloaded> {};
+
+// expected-error@+2 {{'func' is a private member of 'TestClass'}}
+template <typename T>
+using alias3_1 = TemplateClass3<T, &TestClass::func>;
+
+// expected-error@+1 {{'func' is a private member of 'TestClass'}}
+using alias3_2 = TemplateClass3<int, &TestClass::func>;
+
+// expected-error@+2 {{'funcOverloaded' is a private member of 'TestClass'}}
+template <typename T>
+using alias3_3 = TemplateClass3<T, &TestClass::funcOverloaded>;
+
+// expected-error@+1 {{'funcOverloaded' is a private member of 'TestClass'}}
+using alias3_4 = TemplateClass3<int, &TestClass::funcOverloaded>;
+
+// expected-error@+2 {{'func' is a private member of 'TestClass'}}
+template <typename T>
+class TemplateClass3<T, &TestClass::func> varTemplate3_1 {};
+
+// expected-error@+2 {{'funcOverloaded' is a private member of 'TestClass'}}
+template <typename T>
+class TemplateClass3<T, &TestClass::funcOverloaded> varTemplate3_2 {};
+
+template<typename T, void (*)()> class TemplateClass4 {};
+template<typename T> class TemplateClass4<T, &TestClass::staticFunc> {};
+template<typename T> class TemplateClass4<T, &TestClass::staticFuncOverloaded> {};
+
+// expected-error@+2 {{'staticFunc' is a private member of 'TestClass'}}
+template <typename T>
+class TemplateClass4<T, &TestClass::staticFunc> varTemplate4_1 {};
+
+// expected-error@+2 {{'staticFuncOverloaded' is a private member of 'TestClass'}}
+template <typename T>
+class TemplateClass4<T, &TestClass::staticFuncOverloaded> varTemplate4_2 {};
+
+template<typename T> class TemplateClass5 {};
+template<> class TemplateClass5<TestClass::Nested> {};
+
+template<typename T, typename U> class TemplateClass6 {};
+template<typename T> class TemplateClass6<T, TestClass::Nested> {};
+
+// expected-error@+2 {{'Nested' is a private member of 'TestClass'}}
+template <typename T>
+class TemplateClass6<T, TestClass::Nested> varTemplate6_1 {};
+
+template <int TestClass::*> class TemplateClass7 {};
+template <> class TemplateClass7<&TestClass::field> {};
+
+template <typename T, int TestClass::*> class TemplateClass8 {};
+template <typename T> class TemplateClass8<T, &TestClass::field> {};
+
+// expected-error@+2 {{'field' is a private member of 'TestClass'}}
+template <typename T>
+class TemplateClass8<T, &TestClass::field> varTemplate8_1 {};
+
+template<class T>
+struct trait;
+
+class class_ {
+ template<class U>
+ struct impl;
+};
+
+template<class U>
+struct trait<class_::impl<U>>;
Index: clang/test/CXX/drs/dr1xx.cpp
===================================================================
--- clang/test/CXX/drs/dr1xx.cpp
+++ clang/test/CXX/drs/dr1xx.cpp
@@ -919,12 +919,12 @@
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;
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/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/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/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/include/clang/Basic/DeclNodes.td
===================================================================
--- clang/include/clang/Basic/DeclNodes.td
+++ clang/include/clang/Basic/DeclNodes.td
@@ -22,7 +22,7 @@
def Type : DeclNode<Named, "types", 1>;
def TypedefName : DeclNode<Type, "typedefs", 1>;
def Typedef : DeclNode<TypedefName>;
- def TypeAlias : DeclNode<TypedefName>;
+ def TypeAlias : DeclNode<TypedefName>, DeclContext;
def ObjCTypeParam : DeclNode<TypedefName>;
def UnresolvedUsingTypename : DeclNode<Type>;
def Tag : DeclNode<Type, "tag types", 1>, DeclContext;
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/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,
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits