r197298 - PR18232: implement instantiation for class-scope explicit specializations of
Richard Smith
richard-llvm at metafoo.co.uk
Fri Dec 13 17:04:22 PST 2013
Author: rsmith
Date: Fri Dec 13 19:04:22 2013
New Revision: 197298
URL: http://llvm.org/viewvc/llvm-project?rev=197298&view=rev
Log:
PR18232: implement instantiation for class-scope explicit specializations of
class templates (a Microsoft extension).
Added:
cfe/trunk/test/SemaTemplate/ms-class-specialization-class-scope.cpp
Modified:
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=197298&r1=197297&r2=197298&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Dec 13 19:04:22 2013
@@ -1218,7 +1218,7 @@ CXXRecordDecl::setInstantiationOfMemberC
TemplateSpecializationKind TSK) {
assert(TemplateOrInstantiation.isNull() &&
"Previous template or instantiation?");
- assert(!isa<ClassTemplateSpecializationDecl>(this));
+ assert(!isa<ClassTemplatePartialSpecializationDecl>(this));
TemplateOrInstantiation
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
}
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=197298&r1=197297&r2=197298&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Dec 13 19:04:22 2013
@@ -2321,8 +2321,144 @@ Decl *TemplateDeclInstantiator::VisitRec
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(
Added: cfe/trunk/test/SemaTemplate/ms-class-specialization-class-scope.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-class-specialization-class-scope.cpp?rev=197298&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/ms-class-specialization-class-scope.cpp (added)
+++ cfe/trunk/test/SemaTemplate/ms-class-specialization-class-scope.cpp Fri Dec 13 19:04:22 2013
@@ -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}}
More information about the cfe-commits
mailing list