From 4f9c5f006892b9c118de2407ead4a4337c4c6830 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 11 Dec 2015 22:39:52 +0000 Subject: [PATCH] Allow non-defining declarations of class template partial specializations to 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 | 7 ++++- .../dcl.spec/dcl.type/dcl.type.elab/p1.cpp | 26 +++++++++++++++++++ .../Inputs/submodules-merge-defs/defs.h | 7 +++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p1.cpp diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f9c1a01426..203adeab8d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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/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 index 0000000000..e3982fd6a8 --- /dev/null +++ b/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/test/Modules/Inputs/submodules-merge-defs/defs.h b/test/Modules/Inputs/submodules-merge-defs/defs.h index e9d7284719..f6004f0fc8 100644 --- a/test/Modules/Inputs/submodules-merge-defs/defs.h +++ b/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 {}; -- 2.40.0