erik.pilkington updated this revision to Diff 168352.
erik.pilkington added a comment.

Address @rsmith's review comments.


https://reviews.llvm.org/D52521

Files:
  clang/include/clang/AST/DeclTemplate.h
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/member-spec-dr727.cpp

Index: clang/test/SemaCXX/member-spec-dr727.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/member-spec-dr727.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -std=c++17 -verify %s -emit-llvm -o -
+
+// expected-no-diagnostics
+
+namespace PR39031 {
+template <class>
+struct S {
+  template <class>
+  struct Wrapper;
+
+  template <>
+  struct Wrapper<int> {
+    template <class T>
+    void f(T) {
+      T x;
+    }
+  };
+};
+
+void Run() {
+  S<int>::Wrapper<int>().f(1);
+}
+} // namespace PR39031
+
+template <class A, class B> struct is_same { static constexpr bool value = false; };
+template <class A> struct is_same<A, A> { static constexpr bool value = true; };
+
+namespace t1 {
+template <class Ap> struct A {
+  template <class Bp> struct B;
+
+  template <> struct B<short> {
+    template <class Cp> struct C {
+      static_assert(is_same<Cp, int>::value);
+      static_assert(is_same<Ap, char>::value);
+    };
+  };
+};
+
+A<char>::B<short>::C<int> x;
+}
+
+namespace t2 {
+template <class Ap>
+struct A {
+  template <class Bp> static constexpr int p = 0;
+  template <> static constexpr int p<int> = 1;
+};
+
+// FIXME: why aren't we selecting the specialization here?
+static_assert(A<char>::p<int> == 0);
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -71,7 +71,8 @@
             dyn_cast<VarTemplateSpecializationDecl>(D)) {
       // We're done when we hit an explicit specialization.
       if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
-          !isa<VarTemplatePartialSpecializationDecl>(Spec))
+          !isa<VarTemplatePartialSpecializationDecl>(Spec) &&
+          !Spec->isClassScopeSpecialization())
         return Result;
 
       Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
@@ -113,10 +114,19 @@
     // Add template arguments from a class template instantiation.
     if (ClassTemplateSpecializationDecl *Spec
           = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
-      // We're done when we hit an explicit specialization.
+      // We're done when we hit an explicit specialization ...
       if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
-          !isa<ClassTemplatePartialSpecializationDecl>(Spec))
+          !isa<ClassTemplatePartialSpecializationDecl>(Spec)) {
+        // ... unless this explicit specialization is a member of a template
+        // (DR727), in which case we need to skip past it to gather the
+        // enclosing template argument lists.
+        if (Spec->isClassScopeSpecialization()) {
+          Ctx = Spec->getDeclContext();
+          RelativeToPrimary = false;
+          continue;
+        }
         break;
+      }
 
       Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
 
Index: clang/include/clang/AST/DeclTemplate.h
===================================================================
--- clang/include/clang/AST/DeclTemplate.h
+++ clang/include/clang/AST/DeclTemplate.h
@@ -1765,6 +1765,19 @@
     PointOfInstantiation = Loc;
   }
 
+  /// If this class template specialization was declared at class scope, as
+  /// opposed to out-of-line (DR727). For example, G<int> below:
+  ///
+  /// \code
+  /// template <class T> struct S {
+  ///   template <class> struct G {};
+  ///   template <> struct G<int> {};
+  /// };
+  /// \endcode
+  bool isClassScopeSpecialization() const {
+    return !getFirstDecl()->isOutOfLine();
+  }
+
   /// If this class template specialization is an instantiation of
   /// a template (rather than an explicit specialization), return the
   /// class template or class template partial specialization from which it
@@ -2704,6 +2717,19 @@
     return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
   }
 
+  /// If this variable template specialization was declared at class scope, as
+  /// opposed to out-of-line (DR727). For example, v<int> below:
+  ///
+  /// \code
+  /// template <class T> struct S {
+  ///   template <class> static int v;
+  ///   template <> static int v<int>;
+  /// };
+  /// \endcode
+  bool isClassScopeSpecialization() const {
+    return !getFirstDecl()->isOutOfLine();
+  }
+
   void Profile(llvm::FoldingSetNodeID &ID) const {
     Profile(ID, TemplateArgs->asArray(), getASTContext());
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D52521: [... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D525... Erik Pilkington via Phabricator via cfe-commits
    • [PATCH] D525... Erik Pilkington via Phabricator via cfe-commits

Reply via email to