summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Sema/SemaDecl.cpp7
-rw-r--r--clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp26
-rw-r--r--clang/test/Modules/Inputs/submodules-merge-defs/defs.h7
3 files changed, 39 insertions, 1 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f9c1a014260..203adeab8d4 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp
new file mode 100644
index 00000000000..e3982fd6a83
--- /dev/null
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp
@@ -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>;
diff --git a/clang/test/Modules/Inputs/submodules-merge-defs/defs.h b/clang/test/Modules/Inputs/submodules-merge-defs/defs.h
index e9d72847191..f6004f0fc8b 100644
--- a/clang/test/Modules/Inputs/submodules-merge-defs/defs.h
+++ b/clang/test/Modules/Inputs/submodules-merge-defs/defs.h
@@ -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> {};
OpenPOWER on IntegriCloud