]> granicus.if.org Git - clang/commitdiff
Allow non-defining declarations of class template partial specializations to
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 11 Dec 2015 22:39:52 +0000 (22:39 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 11 Dec 2015 22:39:52 +0000 (22:39 +0000)
have a nested name specifier. Strictly speaking, forward declarations of class
template partial specializations are not permitted at all, but that seems like
an obvious wording defect, and if we allow them without a nested name specifier
we should also allow them with a nested name specifier.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@255383 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDecl.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp [new file with mode: 0644]
test/Modules/Inputs/submodules-merge-defs/defs.h

index f9c1a0142602fd30d0e4159f224124cc4d619952..203adeab8d443cc1cec00bc62c9d8127dd2eece0 100644 (file)
@@ -3780,10 +3780,15 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
   bool IsExplicitSpecialization =
     !TemplateParams.empty() && TemplateParams.back()->size() == 0;
   if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() &&
-      !IsExplicitInstantiation && !IsExplicitSpecialization) {
+      !IsExplicitInstantiation && !IsExplicitSpecialization &&
+      !isa<ClassTemplatePartialSpecializationDecl>(Tag)) {
     // Per C++ [dcl.type.elab]p1, a class declaration cannot have a
     // nested-name-specifier unless it is an explicit instantiation
     // or an explicit specialization.
+    //
+    // FIXME: We allow class template partial specializations here too, per the
+    // obvious intent of DR1819.
+    //
     // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either.
     Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier)
         << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << SS.getRange();
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp
new file mode 100644 (file)
index 0000000..e3982fd
--- /dev/null
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -verify %s -std=c++11
+
+namespace N {
+  struct A;
+  template<typename T> struct B {};
+}
+template<typename T> struct C {};
+struct D {
+  template<typename T> struct A {};
+};
+struct N::A; // expected-error {{cannot have a nested name specifier}}
+
+template<typename T> struct N::B; // expected-error {{cannot have a nested name specifier}}
+template<typename T> struct N::B<T*>; // FIXME: This is technically ill-formed, but that's not the intent.
+template<> struct N::B<int>;
+template struct N::B<float>;
+
+template<typename T> struct C;
+template<typename T> struct C<T*>; // FIXME: This is technically ill-formed, but that's not the intent.
+template<> struct C<int>;
+template struct C<float>;
+
+template<typename T> struct D::A; // expected-error {{cannot have a nested name specifier}}
+template<typename T> struct D::A<T*>; // FIXME: This is technically ill-formed, but that's not the intent.
+template<> struct D::A<int>;
+template struct D::A<float>;
index e9d7284719130b7bd98167b4e3b254f577342ec0..f6004f0fc8b239e0766e6f8db8eec21f21869e52 100644 (file)
@@ -131,3 +131,10 @@ namespace ClassTemplatePartialSpec {
   };
   template<typename A, int B> template<typename C> F<A[B]>::F() {}
 }
+
+struct MemberClassTemplate {
+  template<typename T> struct A;
+};
+template<typename T> struct MemberClassTemplate::A {};
+template<typename T> struct MemberClassTemplate::A<T*> {};
+template<> struct MemberClassTemplate::A<int> {};