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

Reply via email to