diff options
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 7 | ||||
-rw-r--r-- | clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp | 26 | ||||
-rw-r--r-- | clang/test/Modules/Inputs/submodules-merge-defs/defs.h | 7 |
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> {}; |