forked from OSchip/llvm-project
Instantiate class member template partial specialization declarations
in the order they occur within the class template, delaying out-of-line member template partial specializations until after the class has been fully instantiated. This fixes a regression introduced by r118454 (itself a fix for PR8001). llvm-svn: 118704
This commit is contained in:
parent
cf7e9a0485
commit
869853eea1
|
@ -13,8 +13,10 @@
|
||||||
#define LLVM_CLANG_SEMA_TEMPLATE_H
|
#define LLVM_CLANG_SEMA_TEMPLATE_H
|
||||||
|
|
||||||
#include "clang/AST/DeclTemplate.h"
|
#include "clang/AST/DeclTemplate.h"
|
||||||
|
#include "clang/AST/DeclVisitor.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
/// \brief Data structure that captures multiple levels of template argument
|
/// \brief Data structure that captures multiple levels of template argument
|
||||||
|
@ -238,6 +240,113 @@ namespace clang {
|
||||||
|
|
||||||
void InstantiatedLocal(const Decl *D, Decl *Inst);
|
void InstantiatedLocal(const Decl *D, Decl *Inst);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TemplateDeclInstantiator
|
||||||
|
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
|
||||||
|
Sema &SemaRef;
|
||||||
|
DeclContext *Owner;
|
||||||
|
const MultiLevelTemplateArgumentList &TemplateArgs;
|
||||||
|
|
||||||
|
/// \brief A list of out-of-line class template partial
|
||||||
|
/// specializations that will need to be instantiated after the
|
||||||
|
/// enclosing class's instantiation is complete.
|
||||||
|
llvm::SmallVector<std::pair<ClassTemplateDecl *,
|
||||||
|
ClassTemplatePartialSpecializationDecl *>, 4>
|
||||||
|
OutOfLinePartialSpecs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
|
||||||
|
const MultiLevelTemplateArgumentList &TemplateArgs)
|
||||||
|
: SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
|
||||||
|
|
||||||
|
// FIXME: Once we get closer to completion, replace these manually-written
|
||||||
|
// declarations with automatically-generated ones from
|
||||||
|
// clang/AST/DeclNodes.inc.
|
||||||
|
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
|
||||||
|
Decl *VisitNamespaceDecl(NamespaceDecl *D);
|
||||||
|
Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
|
||||||
|
Decl *VisitTypedefDecl(TypedefDecl *D);
|
||||||
|
Decl *VisitVarDecl(VarDecl *D);
|
||||||
|
Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
|
||||||
|
Decl *VisitFieldDecl(FieldDecl *D);
|
||||||
|
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
|
||||||
|
Decl *VisitEnumDecl(EnumDecl *D);
|
||||||
|
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
|
||||||
|
Decl *VisitFriendDecl(FriendDecl *D);
|
||||||
|
Decl *VisitFunctionDecl(FunctionDecl *D,
|
||||||
|
TemplateParameterList *TemplateParams = 0);
|
||||||
|
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
|
||||||
|
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
|
||||||
|
TemplateParameterList *TemplateParams = 0);
|
||||||
|
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
|
||||||
|
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
|
||||||
|
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
|
||||||
|
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
|
||||||
|
Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
|
||||||
|
Decl *VisitClassTemplatePartialSpecializationDecl(
|
||||||
|
ClassTemplatePartialSpecializationDecl *D);
|
||||||
|
Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
|
||||||
|
Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
|
||||||
|
Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
|
||||||
|
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
|
||||||
|
Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
|
||||||
|
Decl *VisitUsingDecl(UsingDecl *D);
|
||||||
|
Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
|
||||||
|
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
|
||||||
|
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
|
||||||
|
|
||||||
|
// Base case. FIXME: Remove once we can instantiate everything.
|
||||||
|
Decl *VisitDecl(Decl *D) {
|
||||||
|
unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
|
||||||
|
Diagnostic::Error,
|
||||||
|
"cannot instantiate %0 yet");
|
||||||
|
SemaRef.Diag(D->getLocation(), DiagID)
|
||||||
|
<< D->getDeclKindName();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef
|
||||||
|
llvm::SmallVectorImpl<std::pair<ClassTemplateDecl *,
|
||||||
|
ClassTemplatePartialSpecializationDecl *> >
|
||||||
|
::iterator
|
||||||
|
delayed_partial_spec_iterator;
|
||||||
|
|
||||||
|
/// \brief Return an iterator to the beginning of the set of
|
||||||
|
/// "delayed" partial specializations, which must be passed to
|
||||||
|
/// InstantiateClassTemplatePartialSpecialization once the class
|
||||||
|
/// definition has been completed.
|
||||||
|
delayed_partial_spec_iterator delayed_partial_spec_begin() {
|
||||||
|
return OutOfLinePartialSpecs.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Return an iterator to the end of the set of
|
||||||
|
/// "delayed" partial specializations, which must be passed to
|
||||||
|
/// InstantiateClassTemplatePartialSpecialization once the class
|
||||||
|
/// definition has been completed.
|
||||||
|
delayed_partial_spec_iterator delayed_partial_spec_end() {
|
||||||
|
return OutOfLinePartialSpecs.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions for instantiating methods.
|
||||||
|
TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
|
||||||
|
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
|
||||||
|
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
|
||||||
|
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
|
||||||
|
|
||||||
|
TemplateParameterList *
|
||||||
|
SubstTemplateParams(TemplateParameterList *List);
|
||||||
|
|
||||||
|
bool SubstQualifier(const DeclaratorDecl *OldDecl,
|
||||||
|
DeclaratorDecl *NewDecl);
|
||||||
|
bool SubstQualifier(const TagDecl *OldDecl,
|
||||||
|
TagDecl *NewDecl);
|
||||||
|
|
||||||
|
ClassTemplatePartialSpecializationDecl *
|
||||||
|
InstantiateClassTemplatePartialSpecialization(
|
||||||
|
ClassTemplateDecl *ClassTemplate,
|
||||||
|
ClassTemplatePartialSpecializationDecl *PartialSpec);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // LLVM_CLANG_SEMA_TEMPLATE_H
|
#endif // LLVM_CLANG_SEMA_TEMPLATE_H
|
||||||
|
|
|
@ -1221,6 +1221,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
||||||
if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
|
if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
|
|
||||||
|
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
|
||||||
llvm::SmallVector<Decl*, 4> Fields;
|
llvm::SmallVector<Decl*, 4> Fields;
|
||||||
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
|
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
|
||||||
MemberEnd = Pattern->decls_end();
|
MemberEnd = Pattern->decls_end();
|
||||||
|
@ -1237,7 +1238,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
||||||
if ((*Member)->getDeclContext() != Pattern)
|
if ((*Member)->getDeclContext() != Pattern)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs);
|
if ((*Member)->isInvalidDecl()) {
|
||||||
|
Invalid = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Decl *NewMember = Instantiator.Visit(*Member);
|
||||||
if (NewMember) {
|
if (NewMember) {
|
||||||
if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
|
if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
|
||||||
Fields.push_back(Field);
|
Fields.push_back(Field);
|
||||||
|
@ -1257,7 +1263,22 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
||||||
CheckCompletedCXXClass(Instantiation);
|
CheckCompletedCXXClass(Instantiation);
|
||||||
if (Instantiation->isInvalidDecl())
|
if (Instantiation->isInvalidDecl())
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
|
else {
|
||||||
|
// Instantiate any out-of-line class template partial
|
||||||
|
// specializations now.
|
||||||
|
for (TemplateDeclInstantiator::delayed_partial_spec_iterator
|
||||||
|
P = Instantiator.delayed_partial_spec_begin(),
|
||||||
|
PEnd = Instantiator.delayed_partial_spec_end();
|
||||||
|
P != PEnd; ++P) {
|
||||||
|
if (!Instantiator.InstantiateClassTemplatePartialSpecialization(
|
||||||
|
P->first,
|
||||||
|
P->second)) {
|
||||||
|
Invalid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Exit the scope of this instantiation.
|
// Exit the scope of this instantiation.
|
||||||
SavedContext.pop();
|
SavedContext.pop();
|
||||||
|
|
||||||
|
|
|
@ -25,85 +25,6 @@
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
namespace {
|
|
||||||
class TemplateDeclInstantiator
|
|
||||||
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
|
|
||||||
Sema &SemaRef;
|
|
||||||
DeclContext *Owner;
|
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
|
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs)
|
|
||||||
: SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
|
|
||||||
|
|
||||||
// FIXME: Once we get closer to completion, replace these manually-written
|
|
||||||
// declarations with automatically-generated ones from
|
|
||||||
// clang/AST/DeclNodes.inc.
|
|
||||||
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
|
|
||||||
Decl *VisitNamespaceDecl(NamespaceDecl *D);
|
|
||||||
Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
|
|
||||||
Decl *VisitTypedefDecl(TypedefDecl *D);
|
|
||||||
Decl *VisitVarDecl(VarDecl *D);
|
|
||||||
Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
|
|
||||||
Decl *VisitFieldDecl(FieldDecl *D);
|
|
||||||
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
|
|
||||||
Decl *VisitEnumDecl(EnumDecl *D);
|
|
||||||
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
|
|
||||||
Decl *VisitFriendDecl(FriendDecl *D);
|
|
||||||
Decl *VisitFunctionDecl(FunctionDecl *D,
|
|
||||||
TemplateParameterList *TemplateParams = 0);
|
|
||||||
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
|
|
||||||
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
|
|
||||||
TemplateParameterList *TemplateParams = 0);
|
|
||||||
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
|
|
||||||
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
|
|
||||||
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
|
|
||||||
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
|
|
||||||
Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
|
|
||||||
Decl *VisitClassTemplatePartialSpecializationDecl(
|
|
||||||
ClassTemplatePartialSpecializationDecl *D);
|
|
||||||
Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
|
|
||||||
Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
|
|
||||||
Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
|
|
||||||
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
|
|
||||||
Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
|
|
||||||
Decl *VisitUsingDecl(UsingDecl *D);
|
|
||||||
Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
|
|
||||||
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
|
|
||||||
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
|
|
||||||
|
|
||||||
// Base case. FIXME: Remove once we can instantiate everything.
|
|
||||||
Decl *VisitDecl(Decl *D) {
|
|
||||||
unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
|
|
||||||
Diagnostic::Error,
|
|
||||||
"cannot instantiate %0 yet");
|
|
||||||
SemaRef.Diag(D->getLocation(), DiagID)
|
|
||||||
<< D->getDeclKindName();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functions for instantiating methods.
|
|
||||||
TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
|
|
||||||
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
|
|
||||||
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
|
|
||||||
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
|
|
||||||
|
|
||||||
TemplateParameterList *
|
|
||||||
SubstTemplateParams(TemplateParameterList *List);
|
|
||||||
|
|
||||||
bool SubstQualifier(const DeclaratorDecl *OldDecl,
|
|
||||||
DeclaratorDecl *NewDecl);
|
|
||||||
bool SubstQualifier(const TagDecl *OldDecl,
|
|
||||||
TagDecl *NewDecl);
|
|
||||||
|
|
||||||
bool InstantiateClassTemplatePartialSpecialization(
|
|
||||||
ClassTemplateDecl *ClassTemplate,
|
|
||||||
ClassTemplatePartialSpecializationDecl *PartialSpec);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
|
bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
|
||||||
DeclaratorDecl *NewDecl) {
|
DeclaratorDecl *NewDecl) {
|
||||||
NestedNameSpecifier *OldQual = OldDecl->getQualifier();
|
NestedNameSpecifier *OldQual = OldDecl->getQualifier();
|
||||||
|
@ -860,14 +781,18 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Owner->addDecl(Inst);
|
Owner->addDecl(Inst);
|
||||||
|
|
||||||
// Instantiate all of the partial specializations of this member class
|
if (!PrevClassTemplate) {
|
||||||
// template.
|
// Queue up any out-of-line partial specializations of this member
|
||||||
llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
|
// class template; the client will force their instantiation once
|
||||||
D->getPartialSpecializations(PartialSpecs);
|
// the enclosing class has been instantiated.
|
||||||
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
|
llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
|
||||||
InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]);
|
D->getPartialSpecializations(PartialSpecs);
|
||||||
|
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
|
||||||
|
if (PartialSpecs[I]->isOutOfLine())
|
||||||
|
OutOfLinePartialSpecs.push_back(std::make_pair(Inst, PartialSpecs[I]));
|
||||||
|
}
|
||||||
|
|
||||||
return Inst;
|
return Inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,7 +813,11 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
|
||||||
if (!InstClassTemplate)
|
if (!InstClassTemplate)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return InstClassTemplate->findPartialSpecInstantiatedFromMember(D);
|
if (ClassTemplatePartialSpecializationDecl *Result
|
||||||
|
= InstClassTemplate->findPartialSpecInstantiatedFromMember(D))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
return InstantiateClassTemplatePartialSpecialization(InstClassTemplate, D);
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *
|
Decl *
|
||||||
|
@ -1818,8 +1747,9 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
|
||||||
/// \param PartialSpec the (uninstantiated) class template partial
|
/// \param PartialSpec the (uninstantiated) class template partial
|
||||||
/// specialization that we are instantiating.
|
/// specialization that we are instantiating.
|
||||||
///
|
///
|
||||||
/// \returns true if there was an error, false otherwise.
|
/// \returns The instantiated partial specialization, if successful; otherwise,
|
||||||
bool
|
/// NULL to indicate an error.
|
||||||
|
ClassTemplatePartialSpecializationDecl *
|
||||||
TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
||||||
ClassTemplateDecl *ClassTemplate,
|
ClassTemplateDecl *ClassTemplate,
|
||||||
ClassTemplatePartialSpecializationDecl *PartialSpec) {
|
ClassTemplatePartialSpecializationDecl *PartialSpec) {
|
||||||
|
@ -1833,7 +1763,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
||||||
TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
|
TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
|
||||||
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
|
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
|
||||||
if (!InstParams)
|
if (!InstParams)
|
||||||
return true;
|
return 0;
|
||||||
|
|
||||||
// Substitute into the template arguments of the class template partial
|
// Substitute into the template arguments of the class template partial
|
||||||
// specialization.
|
// specialization.
|
||||||
|
@ -1845,7 +1775,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
||||||
for (unsigned I = 0; I != N; ++I) {
|
for (unsigned I = 0; I != N; ++I) {
|
||||||
TemplateArgumentLoc Loc;
|
TemplateArgumentLoc Loc;
|
||||||
if (SemaRef.Subst(PartialSpecTemplateArgs[I], Loc, TemplateArgs))
|
if (SemaRef.Subst(PartialSpecTemplateArgs[I], Loc, TemplateArgs))
|
||||||
return true;
|
return 0;
|
||||||
InstTemplateArgs.addArgument(Loc);
|
InstTemplateArgs.addArgument(Loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1858,7 +1788,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
||||||
InstTemplateArgs,
|
InstTemplateArgs,
|
||||||
false,
|
false,
|
||||||
Converted))
|
Converted))
|
||||||
return true;
|
return 0;
|
||||||
|
|
||||||
// Figure out where to insert this class template partial specialization
|
// Figure out where to insert this class template partial specialization
|
||||||
// in the member template's set of class template partial specializations.
|
// in the member template's set of class template partial specializations.
|
||||||
|
@ -1905,10 +1835,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
||||||
// Outer<int, int> outer; // error: the partial specializations of Inner
|
// Outer<int, int> outer; // error: the partial specializations of Inner
|
||||||
// // have the same signature.
|
// // have the same signature.
|
||||||
SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared)
|
SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared)
|
||||||
<< WrittenTy;
|
<< WrittenTy->getType();
|
||||||
SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
|
SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
|
||||||
<< SemaRef.Context.getTypeDeclType(PrevDecl);
|
<< SemaRef.Context.getTypeDeclType(PrevDecl);
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1936,7 +1866,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
|
||||||
// Add this partial specialization to the set of class template partial
|
// Add this partial specialization to the set of class template partial
|
||||||
// specializations.
|
// specializations.
|
||||||
ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos);
|
ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos);
|
||||||
return false;
|
return InstPartialSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeSourceInfo*
|
TypeSourceInfo*
|
||||||
|
|
|
@ -53,3 +53,24 @@ struct X0<float>::Inner0<Z*> {
|
||||||
int array3[X0<float>::Inner0<int>::value == 0? 1 : -1];
|
int array3[X0<float>::Inner0<int>::value == 0? 1 : -1];
|
||||||
int array4[X0<float>::Inner0<int*>::value == 3? 1 : -1];
|
int array4[X0<float>::Inner0<int*>::value == 3? 1 : -1];
|
||||||
int array5[X0<float>::Inner0<const int*>::value == 2? 1 : -1];
|
int array5[X0<float>::Inner0<const int*>::value == 2? 1 : -1];
|
||||||
|
|
||||||
|
namespace rdar8651930 {
|
||||||
|
template<typename OuterT>
|
||||||
|
struct Outer {
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct Inner;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Inner<T, T> {
|
||||||
|
static const bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct Inner {
|
||||||
|
static const bool value = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
int array0[Outer<int>::Inner<int, int>::value? 1 : -1];
|
||||||
|
int array1[Outer<int>::Inner<int, float>::value? -1 : 1];
|
||||||
|
}
|
||||||
|
|
|
@ -13,11 +13,9 @@ template<> void X0<char>::f1(type);
|
||||||
namespace PR6161 {
|
namespace PR6161 {
|
||||||
template<typename _CharT>
|
template<typename _CharT>
|
||||||
class numpunct : public locale::facet // expected-error{{use of undeclared identifier 'locale'}} \
|
class numpunct : public locale::facet // expected-error{{use of undeclared identifier 'locale'}} \
|
||||||
// expected-error{{expected class name}} \
|
// expected-error{{expected class name}}
|
||||||
// expected-note{{attempt to specialize declaration here}}
|
|
||||||
{
|
{
|
||||||
static locale::id id; // expected-error{{use of undeclared identifier}}
|
static locale::id id; // expected-error{{use of undeclared identifier}}
|
||||||
};
|
};
|
||||||
numpunct<char>::~numpunct(); // expected-error{{template specialization requires 'template<>'}} \
|
numpunct<char>::~numpunct(); // expected-error{{expected the class name after '~' to name a destructor}}
|
||||||
// expected-error{{specialization of member 'PR6161::numpunct<char>::~numpunct' does not specialize an instantiated member}}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue