forked from OSchip/llvm-project
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. llvm-svn: 255383
This commit is contained in:
parent
c80367417c
commit
84824edd0b
|
@ -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();
|
||||
|
|
|
@ -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>;
|
|
@ -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> {};
|
||||
|
|
Loading…
Reference in New Issue