broadwaylamb created this revision.
broadwaylamb added reviewers: asl, rsmith, doug.gregor, rjmccall, triton.
broadwaylamb added a project: clang.
Herald added subscribers: cfe-commits, dexonsmith.
This patch implements paper P0692R1
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0692r1.html> from the
C++20 standard.
This also fixes a bug (https://llvm.org/PR37424) where explicit instantiations
of templates parameterized by overloaded private member functions were
incorrectly rejected.
This is my first contribution to CFE, so please let me know if I did something
horribly wrong.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D78404
Files:
clang/lib/Parse/ParseDeclCXX.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,44 @@
+// 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>;
+
+// As an extension, this rule is applied to explicit specializations as well.
+template <> class X::Y<A::C> {};
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,61 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// 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 {
+private:
+ void func();
+ void funcOverloaded();
+ void funcOverloaded(int);
+
+ static void staticFunc();
+ static void staticFuncOverloaded();
+ static void staticFuncOverloaded(int);
+
+ class Nested {};
+
+ int field;
+};
+
+template <void (TestClass::*)()> class TemplateClass {};
+template <> class TemplateClass<&TestClass::func> {};
+template <> class TemplateClass<&TestClass::funcOverloaded> {};
+
+template <void (*)()> class TemplateClass2 { };
+template <> class TemplateClass2<&TestClass::staticFunc> {};
+template <> class 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> {};
+
+template<typename T, void (*)()> class TemplateClass4 {};
+template<typename T> class TemplateClass4<T, &TestClass::staticFunc> {};
+template<typename T> class TemplateClass4<T, &TestClass::staticFuncOverloaded> {};
+
+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> {};
+
+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> {};
+
+template<class T>
+struct trait;
+
+class class_ {
+ template<class U>
+ struct impl;
+};
+
+template<class U>
+struct trait<class_::impl<U>>;
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) ||
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits