forked from OSchip/llvm-project
PR18232: implement instantiation for class-scope explicit specializations of
class templates (a Microsoft extension). llvm-svn: 197298
This commit is contained in:
parent
8c79ee409a
commit
8a0dde75f1
|
@ -1218,7 +1218,7 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
|
|||
TemplateSpecializationKind TSK) {
|
||||
assert(TemplateOrInstantiation.isNull() &&
|
||||
"Previous template or instantiation?");
|
||||
assert(!isa<ClassTemplateSpecializationDecl>(this));
|
||||
assert(!isa<ClassTemplatePartialSpecializationDecl>(this));
|
||||
TemplateOrInstantiation
|
||||
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
|
||||
}
|
||||
|
|
|
@ -2321,8 +2321,144 @@ Decl *TemplateDeclInstantiator::VisitRecordDecl(RecordDecl *D) {
|
|||
Decl *
|
||||
TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
|
||||
ClassTemplateSpecializationDecl *D) {
|
||||
llvm_unreachable("Only ClassTemplatePartialSpecializationDecls occur"
|
||||
"inside templates");
|
||||
// As a MS extension, we permit class-scope explicit specialization
|
||||
// of member class templates.
|
||||
ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate();
|
||||
assert(ClassTemplate->getDeclContext()->isRecord() &&
|
||||
D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
|
||||
"can only instantiate an explicit specialization "
|
||||
"for a member class template");
|
||||
|
||||
// Lookup the already-instantiated declaration in the instantiation
|
||||
// of the class template. FIXME: Diagnose or assert if this fails?
|
||||
DeclContext::lookup_result Found
|
||||
= Owner->lookup(ClassTemplate->getDeclName());
|
||||
if (Found.empty())
|
||||
return 0;
|
||||
ClassTemplateDecl *InstClassTemplate
|
||||
= dyn_cast<ClassTemplateDecl>(Found.front());
|
||||
if (!InstClassTemplate)
|
||||
return 0;
|
||||
|
||||
// Substitute into the template arguments of the class template explicit
|
||||
// specialization.
|
||||
TemplateSpecializationTypeLoc Loc = D->getTypeAsWritten()->getTypeLoc().
|
||||
castAs<TemplateSpecializationTypeLoc>();
|
||||
TemplateArgumentListInfo InstTemplateArgs(Loc.getLAngleLoc(),
|
||||
Loc.getRAngleLoc());
|
||||
SmallVector<TemplateArgumentLoc, 4> ArgLocs;
|
||||
for (unsigned I = 0; I != Loc.getNumArgs(); ++I)
|
||||
ArgLocs.push_back(Loc.getArgLoc(I));
|
||||
if (SemaRef.Subst(ArgLocs.data(), ArgLocs.size(),
|
||||
InstTemplateArgs, TemplateArgs))
|
||||
return 0;
|
||||
|
||||
// Check that the template argument list is well-formed for this
|
||||
// class template.
|
||||
SmallVector<TemplateArgument, 4> Converted;
|
||||
if (SemaRef.CheckTemplateArgumentList(InstClassTemplate,
|
||||
D->getLocation(),
|
||||
InstTemplateArgs,
|
||||
false,
|
||||
Converted))
|
||||
return 0;
|
||||
|
||||
// Figure out where to insert this class template explicit specialization
|
||||
// in the member template's set of class template explicit specializations.
|
||||
void *InsertPos = 0;
|
||||
ClassTemplateSpecializationDecl *PrevDecl =
|
||||
InstClassTemplate->findSpecialization(Converted.data(), Converted.size(),
|
||||
InsertPos);
|
||||
|
||||
// Check whether we've already seen a conflicting instantiation of this
|
||||
// declaration (for instance, if there was a prior implicit instantiation).
|
||||
bool Ignored;
|
||||
if (PrevDecl &&
|
||||
SemaRef.CheckSpecializationInstantiationRedecl(D->getLocation(),
|
||||
D->getSpecializationKind(),
|
||||
PrevDecl,
|
||||
PrevDecl->getSpecializationKind(),
|
||||
PrevDecl->getPointOfInstantiation(),
|
||||
Ignored))
|
||||
return 0;
|
||||
|
||||
// If PrevDecl was a definition and D is also a definition, diagnose.
|
||||
// This happens in cases like:
|
||||
//
|
||||
// template<typename T, typename U>
|
||||
// struct Outer {
|
||||
// template<typename X> struct Inner;
|
||||
// template<> struct Inner<T> {};
|
||||
// template<> struct Inner<U> {};
|
||||
// };
|
||||
//
|
||||
// Outer<int, int> outer; // error: the explicit specializations of Inner
|
||||
// // have the same signature.
|
||||
if (PrevDecl && PrevDecl->getDefinition() &&
|
||||
D->isThisDeclarationADefinition()) {
|
||||
SemaRef.Diag(D->getLocation(), diag::err_redefinition) << PrevDecl;
|
||||
SemaRef.Diag(PrevDecl->getDefinition()->getLocation(),
|
||||
diag::note_previous_definition);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create the class template partial specialization declaration.
|
||||
ClassTemplateSpecializationDecl *InstD
|
||||
= ClassTemplateSpecializationDecl::Create(SemaRef.Context,
|
||||
D->getTagKind(),
|
||||
Owner,
|
||||
D->getLocStart(),
|
||||
D->getLocation(),
|
||||
InstClassTemplate,
|
||||
Converted.data(),
|
||||
Converted.size(),
|
||||
PrevDecl);
|
||||
|
||||
// Add this partial specialization to the set of class template partial
|
||||
// specializations.
|
||||
if (!PrevDecl)
|
||||
InstClassTemplate->AddSpecialization(InstD, InsertPos);
|
||||
|
||||
// Substitute the nested name specifier, if any.
|
||||
if (SubstQualifier(D, InstD))
|
||||
return 0;
|
||||
|
||||
// Build the canonical type that describes the converted template
|
||||
// arguments of the class template explicit specialization.
|
||||
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
|
||||
TemplateName(InstClassTemplate), Converted.data(), Converted.size(),
|
||||
SemaRef.Context.getRecordType(InstD));
|
||||
|
||||
// Build the fully-sugared type for this class template
|
||||
// specialization as the user wrote in the specialization
|
||||
// itself. This means that we'll pretty-print the type retrieved
|
||||
// from the specialization's declaration the way that the user
|
||||
// actually wrote the specialization, rather than formatting the
|
||||
// name based on the "canonical" representation used to store the
|
||||
// template arguments in the specialization.
|
||||
TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo(
|
||||
TemplateName(InstClassTemplate), D->getLocation(), InstTemplateArgs,
|
||||
CanonType);
|
||||
|
||||
InstD->setAccess(D->getAccess());
|
||||
InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
|
||||
InstD->setSpecializationKind(D->getSpecializationKind());
|
||||
InstD->setTypeAsWritten(WrittenTy);
|
||||
InstD->setExternLoc(D->getExternLoc());
|
||||
InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc());
|
||||
|
||||
Owner->addDecl(InstD);
|
||||
|
||||
// Instantiate the members of the class-scope explicit specialization eagerly.
|
||||
// We don't have support for lazy instantiation of an explicit specialization
|
||||
// yet, and MSVC eagerly instantiates in this case.
|
||||
if (D->isThisDeclarationADefinition() &&
|
||||
SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs,
|
||||
TSK_ImplicitInstantiation,
|
||||
/*Complain=*/true))
|
||||
return 0;
|
||||
|
||||
return InstD;
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s -Wno-microsoft
|
||||
// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -verify %s -Wno-microsoft
|
||||
|
||||
class A {
|
||||
public:
|
||||
template<typename T> struct X { typedef int x; };
|
||||
|
||||
X<int>::x a; // expected-note {{implicit instantiation first required here}}
|
||||
|
||||
template<> struct X<int>; // expected-error {{explicit specialization of 'A::X<int>' after instantiation}}
|
||||
template<> struct X<char>; // expected-note {{forward declaration}}
|
||||
|
||||
X<char>::x b; // expected-error {{incomplete type 'A::X<char>' named in nested name specifier}}
|
||||
|
||||
template<> struct X<double> {
|
||||
typedef int y;
|
||||
};
|
||||
|
||||
X<double>::y c;
|
||||
|
||||
template<> struct X<float> {}; // expected-note {{previous definition is here}}
|
||||
template<> struct X<float> {}; // expected-error {{redefinition of 'A::X<float>'}}
|
||||
};
|
||||
|
||||
A::X<void>::x axv;
|
||||
A::X<float>::x axf; // expected-error {{no type named 'x'}}
|
||||
|
||||
template<class T> class B {
|
||||
public:
|
||||
template<typename U> struct X { typedef int x; };
|
||||
|
||||
typename X<int>::x a; // expected-note {{implicit instantiation first required here}}
|
||||
|
||||
template<> struct X<int>; // expected-error {{explicit specialization of 'X<int>' after instantiation}}
|
||||
template<> struct X<char>; // expected-note {{forward declaration}}
|
||||
|
||||
typename X<char>::x b; // expected-error {{incomplete type 'B<float>::X<char>' named in nested name specifier}}
|
||||
|
||||
template<> struct X<double> {
|
||||
typedef int y;
|
||||
};
|
||||
|
||||
typename X<double>::y c;
|
||||
|
||||
template<> struct X<float> {}; // expected-note {{previous definition is here}}
|
||||
template<> struct X<T> {}; // expected-error {{redefinition of 'X<float>'}}
|
||||
};
|
||||
|
||||
B<float> b; // expected-note {{in instantiation of}}
|
Loading…
Reference in New Issue