diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f9c1a0142602..203adeab8d44 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(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 000000000000..e3982fd6a838 --- /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 struct B {}; +} +template struct C {}; +struct D { + template struct A {}; +}; +struct N::A; // expected-error {{cannot have a nested name specifier}} + +template struct N::B; // expected-error {{cannot have a nested name specifier}} +template struct N::B; // FIXME: This is technically ill-formed, but that's not the intent. +template<> struct N::B; +template struct N::B; + +template struct C; +template struct C; // FIXME: This is technically ill-formed, but that's not the intent. +template<> struct C; +template struct C; + +template struct D::A; // expected-error {{cannot have a nested name specifier}} +template struct D::A; // FIXME: This is technically ill-formed, but that's not the intent. +template<> struct D::A; +template struct D::A; diff --git a/clang/test/Modules/Inputs/submodules-merge-defs/defs.h b/clang/test/Modules/Inputs/submodules-merge-defs/defs.h index e9d728471913..f6004f0fc8b2 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 template F::F() {} } + +struct MemberClassTemplate { + template struct A; +}; +template struct MemberClassTemplate::A {}; +template struct MemberClassTemplate::A {}; +template<> struct MemberClassTemplate::A {};