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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D78404: [... Sergej Jaskiewicz via Phabricator via cfe-commits

Reply via email to