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) {
|
TemplateSpecializationKind TSK) {
|
||||||
assert(TemplateOrInstantiation.isNull() &&
|
assert(TemplateOrInstantiation.isNull() &&
|
||||||
"Previous template or instantiation?");
|
"Previous template or instantiation?");
|
||||||
assert(!isa<ClassTemplateSpecializationDecl>(this));
|
assert(!isa<ClassTemplatePartialSpecializationDecl>(this));
|
||||||
TemplateOrInstantiation
|
TemplateOrInstantiation
|
||||||
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
|
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2321,8 +2321,144 @@ Decl *TemplateDeclInstantiator::VisitRecordDecl(RecordDecl *D) {
|
||||||
Decl *
|
Decl *
|
||||||
TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
|
TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
|
||||||
ClassTemplateSpecializationDecl *D) {
|
ClassTemplateSpecializationDecl *D) {
|
||||||
llvm_unreachable("Only ClassTemplatePartialSpecializationDecls occur"
|
// As a MS extension, we permit class-scope explicit specialization
|
||||||
"inside templates");
|
// 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(
|
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