diff options
Diffstat (limited to 'clang/lib')
26 files changed, 2717 insertions, 355 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a3718fea338..63b1b0ead18 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1041,13 +1041,20 @@ void ASTContext::eraseDeclAttrs(const Decl *D) { } } +// FIXME: Remove ? MemberSpecializationInfo * ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); - llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos - = InstantiatedFromStaticDataMember.find(Var); - if (Pos == InstantiatedFromStaticDataMember.end()) - return 0; + return getTemplateOrSpecializationInfo(Var) + .dyn_cast<MemberSpecializationInfo *>(); +} + +ASTContext::TemplateOrSpecializationInfo +ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) { + llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos = + TemplateOrInstantiation.find(Var); + if (Pos == TemplateOrInstantiation.end()) + return TemplateOrSpecializationInfo(); return Pos->second; } @@ -1058,10 +1065,16 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, SourceLocation PointOfInstantiation) { assert(Inst->isStaticDataMember() && "Not a static data member"); assert(Tmpl->isStaticDataMember() && "Not a static data member"); - assert(!InstantiatedFromStaticDataMember[Inst] && - "Already noted what static data member was instantiated from"); - InstantiatedFromStaticDataMember[Inst] - = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation); + setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo( + Tmpl, TSK, PointOfInstantiation)); +} + +void +ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst, + TemplateOrSpecializationInfo TSI) { + assert(!TemplateOrInstantiation[Inst] && + "Already noted what the variable was instantiated from"); + TemplateOrInstantiation[Inst] = TSI; } FunctionDecl *ASTContext::getClassScopeSpecializationPattern( @@ -7973,20 +7986,20 @@ MangleContext *ASTContext::createMangleContext() { CXXABI::~CXXABI() {} size_t ASTContext::getSideTableAllocatedMemory() const { - return ASTRecordLayouts.getMemorySize() - + llvm::capacity_in_bytes(ObjCLayouts) - + llvm::capacity_in_bytes(KeyFunctions) - + llvm::capacity_in_bytes(ObjCImpls) - + llvm::capacity_in_bytes(BlockVarCopyInits) - + llvm::capacity_in_bytes(DeclAttrs) - + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember) - + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) - + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) - + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) - + llvm::capacity_in_bytes(OverriddenMethods) - + llvm::capacity_in_bytes(Types) - + llvm::capacity_in_bytes(VariableArrayTypes) - + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); + return ASTRecordLayouts.getMemorySize() + + llvm::capacity_in_bytes(ObjCLayouts) + + llvm::capacity_in_bytes(KeyFunctions) + + llvm::capacity_in_bytes(ObjCImpls) + + llvm::capacity_in_bytes(BlockVarCopyInits) + + llvm::capacity_in_bytes(DeclAttrs) + + llvm::capacity_in_bytes(TemplateOrInstantiation) + + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) + + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) + + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) + + llvm::capacity_in_bytes(OverriddenMethods) + + llvm::capacity_in_bytes(Types) + + llvm::capacity_in_bytes(VariableArrayTypes) + + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); } void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) { diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index deac0c5dfbe..922172701f0 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -106,6 +106,8 @@ namespace clang { bool ImportDefinition(RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind = IDK_Default); + bool ImportDefinition(VarDecl *From, VarDecl *To, + ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, @@ -120,9 +122,12 @@ namespace clang { SmallVectorImpl<TemplateArgument> &ToArgs); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); + bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, + bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); + bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); Decl *VisitDecl(Decl *D); Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); @@ -157,7 +162,9 @@ namespace clang { Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); Decl *VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D); - + Decl *VisitVarTemplateDecl(VarTemplateDecl *D); + Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); + // Importing statements Stmt *VisitStmt(Stmt *S); @@ -2017,6 +2024,21 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, return false; } +bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To, + ImportDefinitionKind Kind) { + if (To->getDefinition()) + return false; + + // FIXME: Can we really import any initializer? Alternatively, we could force + // ourselves to import every declaration of a variable and then only use + // getInit() here. + To->setInit(Importer.Import(const_cast<Expr *>(From->getAnyInitializer()))); + + // FIXME: Other bits to merge? + + return false; +} + bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind) { if (To->getDefinition() || To->isBeingDefined()) { @@ -2162,6 +2184,14 @@ bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord); } +bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, + bool Complain) { + StructuralEquivalenceContext Ctx( + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), false, Complain); + return Ctx.IsStructurallyEquivalent(FromVar, ToVar); +} + bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), @@ -2188,6 +2218,14 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, return Ctx.IsStructurallyEquivalent(From, To); } +bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, + VarTemplateDecl *To) { + StructuralEquivalenceContext Ctx(Importer.getFromContext(), + Importer.getToContext(), + Importer.getNonEquivalentDecls()); + return Ctx.IsStructurallyEquivalent(From, To); +} + Decl *ASTNodeImporter::VisitDecl(Decl *D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); @@ -3092,13 +3130,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { LexicalDC->addDeclInternal(ToVar); // Merge the initializer. - // FIXME: Can we really import any initializer? Alternatively, we could force - // ourselves to import every declaration of a variable and then only use - // getInit() here. - ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer()))); + if (ImportDefinition(D, ToVar)) + return 0; - // FIXME: Other bits to merge? - return ToVar; } @@ -4112,6 +4146,205 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( return D2; } +Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { + // If this variable has a definition in the translation unit we're coming + // from, + // but this particular declaration is not that definition, import the + // definition and map to that. + VarDecl *Definition = + cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition()); + if (Definition && Definition != D->getTemplatedDecl()) { + Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate()); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this variable template. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // We may already have a template of the same name; try to find and match it. + assert(!DC->isFunctionOrMethod() && + "Variable templates cannot be declared at function scope"); + SmallVector<NamedDecl *, 4> ConflictingDecls; + SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + Decl *Found = FoundDecls[I]; + if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) { + if (IsStructuralMatch(D, FoundTemplate)) { + // The variable templates structurally match; call it the same template. + Importer.Imported(D->getTemplatedDecl(), + FoundTemplate->getTemplatedDecl()); + return Importer.Imported(D, FoundTemplate); + } + } + + ConflictingDecls.push_back(FoundDecls[I]); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + + if (!Name) + return 0; + + VarDecl *DTemplated = D->getTemplatedDecl(); + + // Import the type. + QualType T = Importer.Import(DTemplated->getType()); + if (T.isNull()) + return 0; + + // Create the declaration that is being templated. + SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart()); + SourceLocation IdLoc = Importer.Import(DTemplated->getLocation()); + TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo()); + VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc, + IdLoc, Name.getAsIdentifierInfo(), T, + TInfo, DTemplated->getStorageClass()); + D2Templated->setAccess(DTemplated->getAccess()); + D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc())); + D2Templated->setLexicalDeclContext(LexicalDC); + + // Importer.Imported(DTemplated, D2Templated); + // LexicalDC->addDeclInternal(D2Templated); + + // Merge the initializer. + if (ImportDefinition(DTemplated, D2Templated)) + return 0; + + // Create the variable template declaration itself. + TemplateParameterList *TemplateParams = + ImportTemplateParameterList(D->getTemplateParameters()); + if (!TemplateParams) + return 0; + + VarTemplateDecl *D2 = VarTemplateDecl::Create( + Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated, + /*PrevDecl=*/0); + D2Templated->setDescribedVarTemplate(D2); + + D2->setAccess(D->getAccess()); + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); + + // Note the relationship between the variable templates. + Importer.Imported(D, D2); + Importer.Imported(DTemplated, D2Templated); + + if (DTemplated->isThisDeclarationADefinition() && + !D2Templated->isThisDeclarationADefinition()) { + // FIXME: Import definition! + } + + return D2; +} + +Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *D) { + // If this record has a definition in the translation unit we're coming from, + // but this particular declaration is not that definition, import the + // definition and map to that. + VarDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>( + Importer.Import(D->getSpecializedTemplate())); + if (!VarTemplate) + return 0; + + // Import the context of this declaration. + DeclContext *DC = VarTemplate->getDeclContext(); + if (!DC) + return 0; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + // Import the location of this declaration. + SourceLocation StartLoc = Importer.Import(D->getLocStart()); + SourceLocation IdLoc = Importer.Import(D->getLocation()); + + // Import template arguments. + SmallVector<TemplateArgument, 2> TemplateArgs; + if (ImportTemplateArguments(D->getTemplateArgs().data(), + D->getTemplateArgs().size(), TemplateArgs)) + return 0; + + // Try to find an existing specialization with these template arguments. + void *InsertPos = 0; + VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization( + TemplateArgs.data(), TemplateArgs.size(), InsertPos); + if (D2) { + // We already have a variable template specialization with these template + // arguments. + + // FIXME: Check for specialization vs. instantiation errors. + + if (VarDecl *FoundDef = D2->getDefinition()) { + if (!D->isThisDeclarationADefinition() || + IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // variable. + return Importer.Imported(D, FoundDef); + } + } + } else { + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + + // Create a new specialization. + D2 = VarTemplateSpecializationDecl::Create( + Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo, + D->getStorageClass(), TemplateArgs.data(), TemplateArgs.size()); + D2->setSpecializationKind(D->getSpecializationKind()); + D2->setTemplateArgsInfo(D->getTemplateArgsInfo()); + + // Add this specialization to the class template. + VarTemplate->AddSpecialization(D2, InsertPos); + + // Import the qualifier, if any. + D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + + // Add the specialization to this context. + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); + } + Importer.Imported(D, D2); + + if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2)) + return 0; + + return D2; +} + //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 772f7353c36..9562879de6a 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1557,6 +1557,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { llvm_unreachable("Invalid storage class"); } +VarDecl::VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass SC) + : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() { + assert(sizeof(VarDeclBitfields) <= sizeof(unsigned)); + assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned)); + AllBits = 0; + VarDeclBits.SClass = SC; + // Everything else is implicitly initialized to false. +} + VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL, SourceLocation IdL, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, @@ -1952,28 +1963,63 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { } TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) + return Spec->getSpecializationKind(); + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getTemplateSpecializationKind(); return TSK_Undeclared; } +VarTemplateDecl *VarDecl::getDescribedVarTemplate() const { + return getASTContext().getTemplateOrSpecializationInfo(this) + .dyn_cast<VarTemplateDecl *>(); +} + +void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) { + getASTContext().setTemplateOrSpecializationInfo(this, Template); +} + MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { if (isStaticDataMember()) - return getASTContext().getInstantiatedFromStaticDataMember(this); - + // FIXME: Remove ? + // return getASTContext().getInstantiatedFromStaticDataMember(this); + return getASTContext().getTemplateOrSpecializationInfo(this) + .dyn_cast<MemberSpecializationInfo *>(); return 0; } void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation) { - MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); - assert(MSI && "Not an instantiated static data member?"); - MSI->setTemplateSpecializationKind(TSK); - if (TSK != TSK_ExplicitSpecialization && - PointOfInstantiation.isValid() && - MSI->getPointOfInstantiation().isInvalid()) - MSI->setPointOfInstantiation(PointOfInstantiation); + if (VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) { + Spec->setSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + Spec->getPointOfInstantiation().isInvalid()) + Spec->setPointOfInstantiation(PointOfInstantiation); + return; + } + + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { + MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); + return; + } + + llvm_unreachable( + "Not a variable or static data member template specialization"); +} + +void +VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD, + TemplateSpecializationKind TSK) { + assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() && + "Previous template or instantiation?"); + getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 13bde4ca860..e99f7ec5b06 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -538,6 +538,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Namespace; case FunctionTemplate: + case VarTemplate: return IDNS_Ordinary; case ClassTemplate: @@ -560,6 +561,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: case ClassScopeFunctionSpecialization: + case VarTemplateSpecialization: + case VarTemplatePartialSpecialization: case ObjCImplementation: case ObjCCategory: case ObjCCategoryImpl: diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index ac0d54f5011..555800a8bef 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -958,3 +958,248 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0, false, TemplateArgumentListInfo()); } + +//===----------------------------------------------------------------------===// +// VarTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +void VarTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} + +VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + VarTemplateDecl *PrevDecl) { + VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl); + New->setPreviousDeclaration(PrevDecl); + return New; +} + +VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl)); + return new (Mem) VarTemplateDecl(EmptyShell()); +} + +// FIXME: Should this be unified accross class, function and variable +// templates? Perhaps also moved to RedeclarableTemplateDecl? +void VarTemplateDecl::LoadLazySpecializations() const { + Common *CommonPtr = getCommonPtr(); + if (CommonPtr->LazySpecializations) { + ASTContext &Context = getASTContext(); + uint32_t *Specs = CommonPtr->LazySpecializations; + CommonPtr->LazySpecializations = 0; + for (uint32_t I = 0, N = *Specs++; I != N; ++I) + (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + } +} + +llvm::FoldingSetVector<VarTemplateSpecializationDecl> & +VarTemplateDecl::getSpecializations() const { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + +llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & +VarTemplateDecl::getPartialSpecializations() { + LoadLazySpecializations(); + return getCommonPtr()->PartialSpecializations; +} + +RedeclarableTemplateDecl::CommonBase * +VarTemplateDecl::newCommon(ASTContext &C) const { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + +VarTemplateSpecializationDecl * +VarTemplateDecl::findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); +} + +void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, + void *InsertPos) { + if (InsertPos) + getSpecializations().InsertNode(D, InsertPos); + else { + VarTemplateSpecializationDecl *Existing = + getSpecializations().GetOrInsertNode(D); + (void)Existing; + assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); + } + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +VarTemplatePartialSpecializationDecl * +VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs, + InsertPos); +} + +void VarTemplateDecl::AddPartialSpecialization( + VarTemplatePartialSpecializationDecl *D, void *InsertPos) { + if (InsertPos) + getPartialSpecializations().InsertNode(D, InsertPos); + else { + VarTemplatePartialSpecializationDecl *Existing = + getPartialSpecializations().GetOrInsertNode(D); + (void)Existing; + assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); + } + + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +void VarTemplateDecl::getPartialSpecializations( + SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) { + llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &PartialSpecs = + getPartialSpecializations(); + PS.clear(); + PS.resize(PartialSpecs.size()); + for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator + P = PartialSpecs.begin(), + PEnd = PartialSpecs.end(); + P != PEnd; ++P) { + assert(!PS[P->getSequenceNumber()]); + PS[P->getSequenceNumber()] = P->getMostRecentDecl(); + } +} + +VarTemplatePartialSpecializationDecl * +VarTemplateDecl::findPartialSpecInstantiatedFromMember( + VarTemplatePartialSpecializationDecl *D) { + Decl *DCanon = D->getCanonicalDecl(); + for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator + P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); + } + + return 0; +} + +//===----------------------------------------------------------------------===// +// VarTemplateSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +VarTemplateSpecializationDecl::VarTemplateSpecializationDecl( + ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs) + : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T, + TInfo, S), + SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0), + TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)), + SpecializationKind(TSK_Undeclared) {} + +VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK) + : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0, + SC_None), + ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {} + +VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs) { + VarTemplateSpecializationDecl *Result = new (Context) + VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC, + StartLoc, IdLoc, SpecializedTemplate, T, + TInfo, S, Args, NumArgs); + return Result; +} + +VarTemplateSpecializationDecl * +VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + void *Mem = + AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl)); + VarTemplateSpecializationDecl *Result = + new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization); + return Result; +} + +void VarTemplateSpecializationDecl::getNameForDiagnostic( + raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { + NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); + + const TemplateArgumentList &TemplateArgs = getTemplateArgs(); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, TemplateArgs.data(), TemplateArgs.size(), Policy); +} + +VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get<VarTemplateDecl *>(); +} + +void VarTemplateSpecializationDecl::setTemplateArgsInfo( + const TemplateArgumentListInfo &ArgsInfo) { + unsigned N = ArgsInfo.size(); + TemplateArgsInfo.setLAngleLoc(ArgsInfo.getLAngleLoc()); + TemplateArgsInfo.setRAngleLoc(ArgsInfo.getRAngleLoc()); + for (unsigned I = 0; I != N; ++I) + TemplateArgsInfo.addArgument(ArgsInfo[I]); +} + +//===----------------------------------------------------------------------===// +// VarTemplatePartialSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +void VarTemplatePartialSpecializationDecl::anchor() {} + +VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, unsigned NumArgs, + TemplateArgumentLoc *ArgInfos, unsigned NumArgInfos, + unsigned SequenceNumber) + : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization, + DC, StartLoc, IdLoc, SpecializedTemplate, T, + TInfo, S, Args, NumArgs), + TemplateParams(Params), ArgsAsWritten(ArgInfos), + NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), + InstantiatedFromMember(0, false) { + // TODO: The template parameters should be in DC by now. Verify. + // AdoptTemplateParameterList(Params, DC); +} + +VarTemplatePartialSpecializationDecl * +VarTemplatePartialSpecializationDecl::Create( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, unsigned NumArgs, + const TemplateArgumentListInfo &ArgInfos, unsigned SequenceNumber) { + unsigned N = ArgInfos.size(); + TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; + for (unsigned I = 0; I != N; ++I) + ClonedArgs[I] = ArgInfos[I]; + + VarTemplatePartialSpecializationDecl *Result = + new (Context) VarTemplatePartialSpecializationDecl( + Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, + S, Args, NumArgs, ClonedArgs, N, SequenceNumber); + Result->setSpecializationKind(TSK_ExplicitSpecialization); + return Result; +} + +VarTemplatePartialSpecializationDecl * +VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl( + C, ID, sizeof(VarTemplatePartialSpecializationDecl)); + VarTemplatePartialSpecializationDecl *Result = + new (Mem) VarTemplatePartialSpecializationDecl(); + return Result; +} diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 9bce9a0fa3b..ac551d8695b 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -432,7 +432,8 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { if (DC->isFunctionOrMethod() && D->hasLinkage()) while (!DC->isNamespace() && !DC->isTranslationUnit()) DC = getEffectiveParentContext(DC); - if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage) + if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage && + !isa<VarTemplateSpecializationDecl>(D)) return false; } @@ -554,6 +555,13 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { return Spec->getSpecializedTemplate(); } + // Check if we have a variable template. + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); + return Spec->getSpecializedTemplate(); + } + return 0; } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 49364e6b563..970f9781b78 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -37,6 +37,8 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::UnresolvedUsingTypename: case Decl::ClassTemplateSpecialization: case Decl::ClassTemplatePartialSpecialization: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: case Decl::TemplateTypeParm: case Decl::UnresolvedUsingValue: case Decl::NonTypeTemplateParm: @@ -52,6 +54,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::ParmVar: case Decl::ImplicitParam: case Decl::ClassTemplate: + case Decl::VarTemplate: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: case Decl::TemplateTemplateParm: diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 21edc7e6513..dbdf016b31b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2841,8 +2841,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { EmitGlobal(cast<FunctionDecl>(D)); break; - + case Decl::Var: + // Skip variable templates + if (cast<VarDecl>(D)->getDescribedVarTemplate()) + return; + case Decl::VarTemplateSpecialization: EmitGlobal(cast<VarDecl>(D)); break; @@ -2859,6 +2863,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::UsingShadow: case Decl::Using: case Decl::ClassTemplate: + case Decl::VarTemplate: + case Decl::VarTemplatePartialSpecialization: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: case Decl::Block: diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp index 7ed9d36ca3b..f8ee36a50dc 100644 --- a/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/clang/lib/Frontend/MultiplexConsumer.cpp @@ -94,6 +94,9 @@ public: virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D); + virtual void + AddedCXXTemplateSpecialization(const VarTemplateDecl *TD, + const VarTemplateSpecializationDecl *D); virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D); virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType); @@ -135,6 +138,11 @@ void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( Listeners[i]->AddedCXXTemplateSpecialization(TD, D); } void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( + const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedCXXTemplateSpecialization(TD, D); +} +void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( const FunctionTemplateDecl *TD, const FunctionDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedCXXTemplateSpecialization(TD, D); diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index e04685cfa4d..9f832e5195e 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -55,11 +55,11 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, TemplateParams, 0, VS, ICIS_NoInit); if (FnD) { - Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, - false, true); + Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, + true); bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType(); if (Init.isUsable()) - Actions.AddInitializerToDecl(FnD, Init.get(), false, + Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); else Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0b276d0b58f..80fab62f41e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1797,24 +1797,69 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, break; case ParsedTemplateInfo::Template: - case ParsedTemplateInfo::ExplicitSpecialization: + case ParsedTemplateInfo::ExplicitSpecialization: { ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), *TemplateInfo.TemplateParams, D); - break; - case ParsedTemplateInfo::ExplicitInstantiation: { - DeclResult ThisRes - = Actions.ActOnExplicitInstantiation(getCurScope(), - TemplateInfo.ExternLoc, - TemplateInfo.TemplateLoc, - D); - if (ThisRes.isInvalid()) { + // If this is a forward declaration of a variable template or variable + // template partial specialization with nested name specifier, complain. + // FIXME: Move to Sema. + CXXScopeSpec &SS = D.getCXXScopeSpec(); + if (Tok.is(tok::semi) && ThisDecl && SS.isNotEmpty() && + (isa<VarTemplateDecl>(ThisDecl) || + isa<VarTemplatePartialSpecializationDecl>(ThisDecl))) { + Diag(SS.getBeginLoc(), diag::err_forward_var_nested_name_specifier) + << isa<VarTemplatePartialSpecializationDecl>(ThisDecl) + << SS.getRange(); SkipUntil(tok::semi, true, true); return 0; } - ThisDecl = ThisRes.get(); + if (VarTemplateDecl *VT = + ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0) + // Re-direct this decl to refer to the templated decl so that we can + // initialize it. + ThisDecl = VT->getTemplatedDecl(); + break; + } + case ParsedTemplateInfo::ExplicitInstantiation: { + if (Tok.is(tok::semi)) { + DeclResult ThisRes = Actions.ActOnExplicitInstantiation( + getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D); + if (ThisRes.isInvalid()) { + SkipUntil(tok::semi, true, true); + return 0; + } + ThisDecl = ThisRes.get(); + } else { + // FIXME: This check should be for a variable template instantiation only. + + // Check that this is a valid instantiation + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { + // If the declarator-id is not a template-id, issue a diagnostic and + // recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) + << 2 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc); + ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + } else { + SourceLocation LAngleLoc = + PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Recover as if it were an explicit specialization. + TemplateParameterLists FakedParamLists; + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + + ThisDecl = + Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D); + } + } break; } } @@ -1825,6 +1870,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, // If a '==' or '+=' is found, suggest a fixit to '='. if (isTokenEqualOrEqualTypo()) { ConsumeToken(); + if (Tok.is(tok::kw_delete)) { if (D.isFunctionDeclarator()) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 8df15ba75df..e62be697893 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -15,6 +15,7 @@ #include "RAIIObjectsForParser.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" @@ -2264,6 +2265,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, TemplateParams, BitfieldSize.release(), VS, HasInClassInit); + + if (VarTemplateDecl *VT = + ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0) + // Re-direct this decl to refer to the templated decl so that we can + // initialize it. + ThisDecl = VT->getTemplatedDecl(); + if (ThisDecl && AccessAttrs) Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, false, true); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 9704b98d48e..d4a83fb0c9c 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -465,8 +465,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TemplateName, false)) return true; continue; - } - + } + if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && (IsTypename || IsTemplateArgumentList(1))) { // We have something like t::getAs<T>, where getAs is a @@ -561,6 +561,12 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // '::' unqualified-id // CXXScopeSpec SS; + if (Tok.getKind() == tok::annot_template_id) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + // FIXME: This is a hack for now. It may need to be done from within + // ParseUnqualifiedId(), or most likely ParseOptionalCXXScopeSpecifier(); + SS = TemplateId->SS; + } ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); SourceLocation TemplateKWLoc; diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index d8ad2597115..fa23bd1face 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -242,32 +242,31 @@ Parser::ParseSingleDeclarationAfterTemplate( // If the declarator-id is not a template-id, issue a diagnostic and // recover by ignoring the 'template' keyword. Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0; - return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(), - &LateParsedAttrs); + return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(), + &LateParsedAttrs); } else { SourceLocation LAngleLoc = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); - Diag(DeclaratorInfo.getIdentifierLoc(), + Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_explicit_instantiation_with_definition) - << SourceRange(TemplateInfo.TemplateLoc) - << FixItHint::CreateInsertion(LAngleLoc, "<>"); + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); - // Recover as if it were an explicit specialization. + // Recover as if it were an explicit specialization. TemplateParameterLists FakedParamLists; - FakedParamLists.push_back( - Actions.ActOnTemplateParameterList(0, SourceLocation(), - TemplateInfo.TemplateLoc, - LAngleLoc, 0, 0, LAngleLoc)); - - return ParseFunctionDefinition(DeclaratorInfo, - ParsedTemplateInfo(&FakedParamLists, - /*isSpecialization=*/true, - /*LastParamListWasEmpty=*/true), - &LateParsedAttrs); + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + + return ParseFunctionDefinition( + DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists, + /*isSpecialization=*/true, + /*LastParamListWasEmpty=*/true), + &LateParsedAttrs); } } return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, - &LateParsedAttrs); + &LateParsedAttrs); } // Parse this declaration. diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 036278f72ed..8f894818bb4 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1437,8 +1437,9 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, return ANK_TemplateName; } // Fall through. + case Sema::NC_VarTemplate: case Sema::NC_FunctionTemplate: { - // We have a type or function template followed by '<'. + // We have a type, variable or function template followed by '<'. ConsumeToken(); UnqualifiedId Id; Id.setIdentifier(Name, NameLoc); @@ -1653,7 +1654,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, // annotation token to a type annotation token now. AnnotateTemplateIdTokenAsType(); return false; - } + } else if (TemplateId->Kind == TNK_Var_template) + return false; } if (SS.isEmpty()) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index aca71b05928..80ac1167ffa 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -799,6 +799,7 @@ Corrected: if (!Result.empty()) { bool IsFunctionTemplate; + bool IsVarTemplate; TemplateName Template; if (Result.end() - Result.begin() > 1) { IsFunctionTemplate = true; @@ -808,7 +809,8 @@ Corrected: TemplateDecl *TD = cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl()); IsFunctionTemplate = isa<FunctionTemplateDecl>(TD); - + IsVarTemplate = isa<VarTemplateDecl>(TD); + if (SS.isSet() && !SS.isInvalid()) Template = Context.getQualifiedTemplateName(SS.getScopeRep(), /*TemplateKeyword=*/false, @@ -825,8 +827,9 @@ Corrected: return NameClassification::FunctionTemplate(Template); } - - return NameClassification::TypeTemplate(Template); + + return IsVarTemplate ? NameClassification::VarTemplate(Template) + : NameClassification::TypeTemplate(Template); } } @@ -3013,8 +3016,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous, if (getLangOpts().CPlusPlus && New->isThisDeclarationADefinition() == VarDecl::Definition && (Def = Old->getDefinition())) { - Diag(New->getLocation(), diag::err_redefinition) - << New->getDeclName(); + Diag(New->getLocation(), diag::err_redefinition) << New; Diag(Def->getLocation(), diag::note_previous_definition); New->setInvalidDecl(); return; @@ -4258,8 +4260,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, TemplateParamLists, AddToScope); } else { - New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, - TemplateParamLists); + New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists, + AddToScope); } if (New == 0) @@ -4768,10 +4770,11 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) { llvm_unreachable("Unexpected context"); } -NamedDecl* +NamedDecl * Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists) { + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope) { QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); @@ -4862,7 +4865,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - bool isExplicitSpecialization = false; + bool IsExplicitSpecialization = false; + bool IsVariableTemplateSpecialization = false; + bool IsPartialSpecialization = false; + bool Invalid = false; // TODO: Can we remove this (error-prone)? + TemplateParameterList *TemplateParams = 0; + VarTemplateDecl *PrevVarTemplate = 0; VarDecl *NewVD; if (!getLangOpts().CPlusPlus) { NewVD = VarDecl::Create(Context, DC, D.getLocStart(), @@ -4922,23 +4930,20 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + NamedDecl *PrevDecl = 0; + if (Previous.begin() != Previous.end()) + PrevDecl = (*Previous.begin())->getUnderlyingDecl(); + PrevVarTemplate = dyn_cast_or_null<VarTemplateDecl>(PrevDecl); + // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. - isExplicitSpecialization = false; - bool Invalid = false; - if (TemplateParameterList *TemplateParams = - MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), TemplateParamLists, - /*never a friend*/ false, isExplicitSpecialization, Invalid)) { - if (TemplateParams->size() > 0) { - // There is no such thing as a variable template. - Diag(D.getIdentifierLoc(), diag::err_template_variable) - << II - << SourceRange(TemplateParams->getTemplateLoc(), - TemplateParams->getRAngleLoc()); - return 0; - } else { + TemplateParams = MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), + D.getCXXScopeSpec(), TemplateParamLists, + /*never a friend*/ false, IsExplicitSpecialization, Invalid); + if (TemplateParams) { + if (!TemplateParams->size() && + D.getName().getKind() != UnqualifiedId::IK_TemplateId) { // There is an extraneous 'template<>' for this variable. Complain // about it, but allow the declaration of the variable. Diag(TemplateParams->getTemplateLoc(), @@ -4946,12 +4951,116 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); + } else { + // Only C++1y supports variable templates (N3651). + Diag(D.getIdentifierLoc(), + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_variable_template + : diag::ext_variable_template); + + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + // This is an explicit specialization or a partial specialization. + // Check that we can declare a specialization here + + IsVariableTemplateSpecialization = true; + IsPartialSpecialization = TemplateParams->size() > 0; + + } else { // if (TemplateParams->size() > 0) + // This is a template declaration. + + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParams)) + return 0; + + // If there is a previous declaration with the same name, check + // whether this is a valid redeclaration. + if (PrevDecl && !isDeclInScope(PrevDecl, DC, S)) + PrevDecl = PrevVarTemplate = 0; + + if (PrevVarTemplate) { + // Ensure that the template parameter lists are compatible. + if (!TemplateParameterListsAreEqual( + TemplateParams, PrevVarTemplate->getTemplateParameters(), + /*Complain=*/true, TPL_TemplateMatch)) + return 0; + } else if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } else if (PrevDecl) { + // C++ [temp]p5: + // ... a template name declared in namespace scope or in class + // scope shall be unique in that scope. + Diag(D.getIdentifierLoc(), diag::err_redefinition_different_kind) + << Name; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + return 0; + } + + // Check the template parameter list of this declaration, possibly + // merging in the template parameter list from the previous variable + // template declaration. + if (CheckTemplateParameterList( + TemplateParams, + PrevVarTemplate ? PrevVarTemplate->getTemplateParameters() + : 0, + (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && + DC->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_VarTemplate)) + Invalid = true; + + if (D.getCXXScopeSpec().isSet()) { + // If the name of the template was qualified, we must be defining + // the template out-of-line. + if (!D.getCXXScopeSpec().isInvalid() && !Invalid && + !PrevVarTemplate) { + Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) + << Name << DC << D.getCXXScopeSpec().getRange(); + Invalid = true; + } + } + } } + } else if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + + // We have encountered something that the user meant to be a + // specialization (because it has explicitly-specified template + // arguments) but that was not introduced with a "template<>" (or had + // too few of them). + // FIXME: Differentiate between attempts for explicit instantiations + // (starting with "template") and the rest. + Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) + << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(), + "template<> "); + IsVariableTemplateSpecialization = true; } - NewVD = VarDecl::Create(Context, DC, D.getLocStart(), - D.getIdentifierLoc(), II, - R, TInfo, SC); + if (IsVariableTemplateSpecialization) { + if (!PrevVarTemplate) { + Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template) + << IsPartialSpecialization; + return 0; + } + + SourceLocation TemplateKWLoc = + TemplateParamLists.size() > 0 + ? TemplateParamLists[0]->getTemplateLoc() + : SourceLocation(); + DeclResult Res = ActOnVarTemplateSpecialization( + S, PrevVarTemplate, D, TInfo, TemplateKWLoc, TemplateParams, SC, + IsPartialSpecialization); + if (Res.isInvalid()) + return 0; + NewVD = cast<VarDecl>(Res.get()); + AddToScope = false; + } else + NewVD = VarDecl::Create(Context, DC, D.getLocStart(), + D.getIdentifierLoc(), II, R, TInfo, SC); // If this decl has an auto type in need of deduction, make a note of the // Decl so we can diagnose uses of it in its own initializer. @@ -4963,7 +5072,14 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, SetNestedNameSpecifier(NewVD, D); - if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) { + // FIXME: Do we need D.getCXXScopeSpec().isSet()? + if (TemplateParams && TemplateParamLists.size() > 1 && + (!IsVariableTemplateSpecialization || D.getCXXScopeSpec().isSet())) { + NewVD->setTemplateParameterListsInfo( + Context, TemplateParamLists.size() - 1, TemplateParamLists.data()); + } else if (IsVariableTemplateSpecialization || + (!TemplateParams && TemplateParamLists.size() > 0 && + (D.getCXXScopeSpec().isSet()))) { NewVD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), TemplateParamLists.data()); @@ -5020,7 +5136,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } if (D.getDeclSpec().isModulePrivateSpecified()) { - if (isExplicitSpecialization) + if (IsVariableTemplateSpecialization) + Diag(NewVD->getLocation(), diag::err_module_private_specialization) + << (IsPartialSpecialization ? 1 : 0) + << FixItHint::CreateRemoval( + D.getDeclSpec().getModulePrivateSpecLoc()); + else if (IsExplicitSpecialization) Diag(NewVD->getLocation(), diag::err_module_private_specialization) << 2 << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); @@ -5089,15 +5210,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Diagnose shadowed variables before filtering for scope. + // FIXME: Special treatment for static variable template members (?). if (!D.getCXXScopeSpec().isSet()) CheckShadow(S, NewVD, Previous); // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). - FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewVD), - isExplicitSpecialization); - + FilterLookupForScope( + Previous, DC, S, shouldConsiderLinkage(NewVD), + IsExplicitSpecialization || IsVariableTemplateSpecialization); + if (!getLangOpts().CPlusPlus) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); } else { @@ -5121,10 +5244,19 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->setInvalidDecl(); } - D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + if (!IsVariableTemplateSpecialization) { + if (PrevVarTemplate) { + LookupResult PrevDecl(*this, GetNameForDeclarator(D), + LookupOrdinaryName, ForRedeclaration); + PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl()); + D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl)); + } else + D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + } // This is an explicit specialization of a static data member. Check it. - if (isExplicitSpecialization && !NewVD->isInvalidDecl() && + // FIXME: Special treatment for static variable template members (?). + if (IsExplicitSpecialization && !NewVD->isInvalidDecl() && CheckMemberSpecialization(NewVD, Previous)) NewVD->setInvalidDecl(); } @@ -5147,7 +5279,45 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - return NewVD; + // If this is not a variable template, return it now + if (!TemplateParams || IsVariableTemplateSpecialization) + return NewVD; + + // If this is supposed to be a variable template, create it as such. + VarTemplateDecl *NewTemplate = + VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name, + TemplateParams, NewVD, PrevVarTemplate); + NewVD->setDescribedVarTemplate(NewTemplate); + + if (D.getDeclSpec().isModulePrivateSpecified()) + NewTemplate->setModulePrivate(); + + // If we are providing an explicit specialization of a static variable + // template, make a note of that. + if (PrevVarTemplate && PrevVarTemplate->getInstantiatedFromMemberTemplate()) + NewTemplate->setMemberSpecialization(); + + // Set the lexical context of this template + NewTemplate->setLexicalDeclContext(CurContext); + if (NewVD->isStaticDataMember() && NewVD->isOutOfLine()) + NewTemplate->setAccess(NewVD->getAccess()); + + if (PrevVarTemplate) + mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl()); + + AddPushedVisibilityAttribute(NewVD); + + PushOnScopeChains(NewTemplate, S); + AddToScope = false; + + if (Invalid) { + NewTemplate->setInvalidDecl(); + NewVD->setInvalidDecl(); + } + + ActOnDocumentableDecl(NewTemplate); + + return NewTemplate; } /// \brief Diagnose variable or built-in function shadowing. Implements @@ -6705,6 +6875,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // specialization (because it has explicitly-specified template // arguments) but that was not introduced with a "template<>" (or had // too few of them). + // FIXME: Differentiate between attempts for explicit instantiations + // (starting with "template") and the rest. Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) << FixItHint::CreateInsertion( @@ -7666,7 +7838,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, RealDecl->setInvalidDecl(); return; } - ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3df0472df6b..bd8b566769c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2001,10 +2001,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Member->setAccess(AS); - // If we have declared a member function template, set the access of the - // templated declaration as well. + // If we have declared a member function template or static data member + // template, set the access of the templated declaration as well. if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member)) FunTmpl->getTemplatedDecl()->setAccess(AS); + else if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(Member)) + VarTmpl->getTemplatedDecl()->setAccess(AS); } if (VS.isOverrideSpecified()) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 8d370ce9063..8038a4502ab 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1559,7 +1559,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, ExprResult Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, - const CXXScopeSpec *SS, NamedDecl *FoundD) { + const CXXScopeSpec *SS, NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs) { if (getLangOpts().CUDA) if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) { @@ -1578,12 +1579,24 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, (CurContext != D->getDeclContext() && D->getDeclContext()->isFunctionOrMethod()); - DeclRefExpr *E = DeclRefExpr::Create(Context, - SS ? SS->getWithLocInContext(Context) - : NestedNameSpecifierLoc(), - SourceLocation(), - D, refersToEnclosingScope, - NameInfo, Ty, VK, FoundD); + DeclRefExpr *E; + if (isa<VarTemplateSpecializationDecl>(D)) { + VarTemplateSpecializationDecl *VarSpec = + cast<VarTemplateSpecializationDecl>(D); + + E = DeclRefExpr::Create( + Context, + SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(), + VarSpec->getTemplateKeywordLoc(), D, refersToEnclosingScope, + NameInfo.getLoc(), Ty, VK, FoundD, TemplateArgs); + } else { + assert(!TemplateArgs && "No template arguments for non-variable" + " template specialization referrences"); + E = DeclRefExpr::Create( + Context, + SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(), + SourceLocation(), D, refersToEnclosingScope, NameInfo, Ty, VK, FoundD); + } MarkDeclRefReferenced(E); @@ -1870,7 +1883,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S, bool IsInlineAsmIdentifier) { assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); - if (SS.isInvalid()) return ExprError(); @@ -1961,6 +1973,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen); if (R.empty() && !ADL) { + // Otherwise, this could be an implicitly declared function reference (legal // in C90, extension in C99, forbidden in C++). if (HasTrailingLParen && II && !getLangOpts().CPlusPlus) { @@ -2056,8 +2069,19 @@ ExprResult Sema::ActOnIdExpression(Scope *S, R, TemplateArgs); } - if (TemplateArgs || TemplateKWLoc.isValid()) + if (TemplateArgs || TemplateKWLoc.isValid()) { + + // In C++1y, if this is a variable template id, then check it + // in BuildTemplateIdExpr(). + // The single lookup result must be a variable template declaration. + if (Id.getKind() == UnqualifiedId::IK_TemplateId && Id.TemplateId && + Id.TemplateId->Kind == TNK_Var_template) { + assert(R.getAsSingle<VarTemplateDecl>() && + "There should only be one declaration found."); + } + return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs); + } return BuildDeclarationNameExpr(SS, R, ADL); } @@ -2524,10 +2548,9 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, } /// \brief Complete semantic analysis for a reference to the given declaration. -ExprResult -Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo, - NamedDecl *D, NamedDecl *FoundD) { +ExprResult Sema::BuildDeclarationNameExpr( + const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, + NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { assert(D && "Cannot refer to a NULL declaration"); assert(!isa<FunctionTemplateDecl>(D) && "Cannot refer unambiguously to a function template"); @@ -2539,8 +2562,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { // Specifically diagnose references to class templates that are missing // a template argument list. - Diag(Loc, diag::err_template_decl_ref) - << Template << SS.getRange(); + Diag(Loc, diag::err_template_decl_ref) << (isa<VarTemplateDecl>(D) ? 1 : 0) + << Template << SS.getRange(); Diag(Template->getLocation(), diag::note_template_decl_here); return ExprError(); } @@ -2630,6 +2653,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, } case Decl::Var: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: // In C, "extern void blah;" is valid and is an r-value. if (!getLangOpts().CPlusPlus && !type.hasQualifiers() && @@ -2727,7 +2752,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, break; } - return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD); + return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, + TemplateArgs); } } @@ -11690,28 +11716,64 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, if (!IsPotentiallyEvaluatedContext(SemaRef)) return; - // Implicit instantiation of static data members of class templates. - if (Var->isStaticDataMember() && Var->getInstantiatedFromStaticDataMember()) { + VarTemplateSpecializationDecl *VarSpec = + dyn_cast<VarTemplateSpecializationDecl>(Var); + + // Implicit instantiation of static data members, static data member + // templates of class templates, and variable template specializations. + // Delay instantiations of variable templates, except for those + // that could be used in a constant expression. + if (VarSpec || (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember())) { MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); - assert(MSInfo && "Missing member specialization information?"); - bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid(); - if (MSInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation && - (!AlreadyInstantiated || - Var->isUsableInConstantExpressions(SemaRef.Context))) { - if (!AlreadyInstantiated) { - // This is a modification of an existing AST node. Notify listeners. - if (ASTMutationListener *L = SemaRef.getASTMutationListener()) - L->StaticDataMemberInstantiated(Var); - MSInfo->setPointOfInstantiation(Loc); + if (VarSpec) + assert(!isa<VarTemplatePartialSpecializationDecl>(Var) && + "Can't instantiate a partial template specialization."); + if (Var->isStaticDataMember()) + assert(MSInfo && "Missing member specialization information?"); + + SourceLocation PointOfInstantiation; + bool InstantiationIsOkay = true; + if (MSInfo) { + bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid(); + TemplateSpecializationKind TSK = MSInfo->getTemplateSpecializationKind(); + + if (TSK == TSK_ImplicitInstantiation && + (!AlreadyInstantiated || + Var->isUsableInConstantExpressions(SemaRef.Context))) { + if (!AlreadyInstantiated) { + // This is a modification of an existing AST node. Notify listeners. + if (ASTMutationListener *L = SemaRef.getASTMutationListener()) + L->StaticDataMemberInstantiated(Var); + MSInfo->setPointOfInstantiation(Loc); + } + PointOfInstantiation = MSInfo->getPointOfInstantiation(); + } else + InstantiationIsOkay = false; + } else { + if (VarSpec->getPointOfInstantiation().isInvalid()) + VarSpec->setPointOfInstantiation(Loc); + PointOfInstantiation = VarSpec->getPointOfInstantiation(); + } + + if (InstantiationIsOkay) { + bool InstantiationDependent = false; + bool IsNonDependent = + VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments( + VarSpec->getTemplateArgsInfo(), InstantiationDependent) + : true; + + // Do not instantiate specializations that are still type-dependent. + if (IsNonDependent) { + if (Var->isUsableInConstantExpressions(SemaRef.Context)) { + // Do not defer instantiations of variables which could be used in a + // constant expression. + SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); + } else { + SemaRef.PendingInstantiations + .push_back(std::make_pair(Var, PointOfInstantiation)); + } } - SourceLocation PointOfInstantiation = MSInfo->getPointOfInstantiation(); - if (Var->isUsableInConstantExpressions(SemaRef.Context)) - // Do not defer instantiations of variables which could be used in a - // constant expression. - SemaRef.InstantiateStaticDataMemberDefinition(PointOfInstantiation,Var); - else - SemaRef.PendingInstantiations.push_back( - std::make_pair(Var, PointOfInstantiation)); } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index af0eb08f203..098187244a6 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -11,6 +11,7 @@ #include "TreeTransform.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" @@ -207,8 +208,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S, R.suppressDiagnostics(); } else { assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) || - isa<TypeAliasTemplateDecl>(TD)); - TemplateKind = TNK_Type_template; + isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD)); + TemplateKind = + isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template; } } @@ -1159,6 +1161,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, SourceRange DefArgRange) { switch (TPC) { case Sema::TPC_ClassTemplate: + case Sema::TPC_VarTemplate: case Sema::TPC_TypeAliasTemplate: return false; @@ -1430,7 +1433,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // If a template parameter of a primary class template or alias template // is a template parameter pack, it shall be the last template parameter. if (SawParameterPack && (NewParam + 1) != NewParamEnd && - (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) { + (TPC == TPC_ClassTemplate || TPC == TPC_VarTemplate || + TPC == TPC_TypeAliasTemplate)) { Diag((*NewParam)->getLocation(), diag::err_template_param_pack_must_be_last_template_parameter); Invalid = true; @@ -1924,11 +1928,14 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( void Sema::NoteAllFoundTemplates(TemplateName Name) { if (TemplateDecl *Template = Name.getAsTemplateDecl()) { Diag(Template->getLocation(), diag::note_template_declared_here) - << (isa<FunctionTemplateDecl>(Template)? 0 - : isa<ClassTemplateDecl>(Template)? 1 - : isa<TypeAliasTemplateDecl>(Template)? 2 - : 3) - << Template->getDeclName(); + << (isa<FunctionTemplateDecl>(Template) + ? 0 + : isa<ClassTemplateDecl>(Template) + ? 1 + : isa<VarTemplateDecl>(Template) + ? 2 + : isa<TypeAliasTemplateDecl>(Template) ? 3 : 4) + << Template->getDeclName(); return; } @@ -2263,6 +2270,452 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } +static bool CheckTemplatePartialSpecializationArgs( + Sema &S, TemplateParameterList *TemplateParams, + SmallVectorImpl<TemplateArgument> &TemplateArgs); + +static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, + NamedDecl *PrevDecl, + SourceLocation Loc, + bool IsPartialSpecialization); + +static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D); +/* +/// \brief Check the new variable specialization against the parsed input. +/// +/// FIXME: Model this against function specializations where +/// a new function declaration is checked against the specialization +/// as candidate for redefinition... (?) +static bool CheckVariableTemplateSpecializationType() { + + if (ExpectedType is undeduced && ParsedType is not undeduced) + ExpectedType = dedudeType(); + + if (both types are undeduced) + ???; + + bool CheckType = !ExpectedType()-> + + if (!Context.hasSameType(DI->getType(), ExpectedDI->getType())) { + unsigned ErrStr = IsPartialSpecialization ? 2 : 1; + Diag(D.getIdentifierLoc(), diag::err_invalid_var_template_spec_type) + << ErrStr << VarTemplate << DI->getType() << ExpectedDI->getType(); + Diag(VarTemplate->getLocation(), diag::note_template_declared_here) + << 2 << VarTemplate->getDeclName(); + return true; + } +} +*/ + +DeclResult Sema::ActOnVarTemplateSpecialization( + Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI, + SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, + VarDecl::StorageClass SC, bool IsPartialSpecialization) { + assert(VarTemplate && "A variable template id without template?"); + + // D must be variable template id. + assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId && + "Variable template specialization is declared with a template it."); + + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + SourceLocation TemplateNameLoc = D.getIdentifierLoc(); + SourceLocation LAngleLoc = TemplateId->LAngleLoc; + SourceLocation RAngleLoc = TemplateId->RAngleLoc; + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); + translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + TemplateName Name(VarTemplate); + + // Check for unexpanded parameter packs in any of the template arguments. + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + if (DiagnoseUnexpandedParameterPack(TemplateArgs[I], + UPPC_PartialSpecialization)) + return true; + + // Check that the template argument list is well-formed for this + // template. + SmallVector<TemplateArgument, 4> Converted; + if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, + false, Converted)) + return true; + + // Check that the type of this variable template specialization + // matches the expected type. + TypeSourceInfo *ExpectedDI; + { + // Do substitution on the type of the declaration + TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + InstantiatingTemplate Inst(*this, TemplateKWLoc, VarTemplate); + if (Inst) + return true; + VarDecl *Templated = VarTemplate->getTemplatedDecl(); + ExpectedDI = + SubstType(Templated->getTypeSourceInfo(), + MultiLevelTemplateArgumentList(TemplateArgList), + Templated->getTypeSpecStartLoc(), Templated->getDeclName()); + } + if (!ExpectedDI) + return true; + + /* + // Check the new variable specialization against the parsed input. + // (Attributes are merged later below.) + if (CheckVariableTemplateSpecializationType()) + return true; + */ + + // Find the variable template (partial) specialization declaration that + // corresponds to these arguments. + if (IsPartialSpecialization) { + if (CheckTemplatePartialSpecializationArgs( + *this, VarTemplate->getTemplateParameters(), Converted)) + return true; + + bool InstantiationDependent; + if (!Name.isDependent() && + !TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs.getArgumentArray(), TemplateArgs.size(), + InstantiationDependent)) { + Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) + << VarTemplate->getDeclName(); + IsPartialSpecialization = false; + } + } + + void *InsertPos = 0; + VarTemplateSpecializationDecl *PrevDecl = 0; + + if (IsPartialSpecialization) + // FIXME: Template parameter list matters too + PrevDecl = VarTemplate->findPartialSpecialization( + Converted.data(), Converted.size(), InsertPos); + else + PrevDecl = VarTemplate->findSpecialization(Converted.data(), + Converted.size(), InsertPos); + + VarTemplateSpecializationDecl *Specialization = 0; + + // Check whether we can declare a variable template specialization in + // the current scope. + if (CheckTemplateSpecializationScope(*this, VarTemplate, PrevDecl, + TemplateNameLoc, + IsPartialSpecialization)) + return true; + + if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) { + // Since the only prior variable template specialization with these + // arguments was referenced but not declared, reuse that + // declaration node as our own, updating its source location and + // the list of outer template parameters to reflect our new declaration. + Specialization = PrevDecl; + Specialization->setLocation(TemplateNameLoc); + PrevDecl = 0; + } else if (IsPartialSpecialization) { + // Create a new class template partial specialization declaration node. + VarTemplatePartialSpecializationDecl *PrevPartial = + cast_or_null<VarTemplatePartialSpecializationDecl>(PrevDecl); + unsigned SequenceNumber = + PrevPartial ? PrevPartial->getSequenceNumber() + : VarTemplate->getNextPartialSpecSequenceNumber(); + VarTemplatePartialSpecializationDecl *Partial = + VarTemplatePartialSpecializationDecl::Create( + Context, VarTemplate->getDeclContext(), TemplateKWLoc, + TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, + Converted.data(), Converted.size(), TemplateArgs, SequenceNumber); + + if (!PrevPartial) + VarTemplate->AddPartialSpecialization(Partial, InsertPos); + Specialization = Partial; + + // If we are providing an explicit specialization of a member variable + // template specialization, make a note of that. + if (PrevPartial && PrevPartial->getInstantiatedFromMember()) + Partial->setMemberSpecialization(); + + // Check that all of the template parameters of the variable template + // partial specialization are deducible from the template + // arguments. If not, this variable template partial specialization + // will never be used. + llvm::SmallBitVector DeducibleParams(TemplateParams->size()); + MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + TemplateParams->getDepth(), DeducibleParams); + + if (!DeducibleParams.all()) { + unsigned NumNonDeducible = + DeducibleParams.size() - DeducibleParams.count(); + Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) + << (NumNonDeducible > 1) << SourceRange(TemplateNameLoc, RAngleLoc); + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); + if (Param->getDeclName()) + Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) + << Param->getDeclName(); + else + Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) + << "<anonymous>"; + } + } + } + } else { + // Create a new class template specialization declaration node for + // this explicit specialization or friend declaration. + Specialization = VarTemplateSpecializationDecl::Create( + Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, + VarTemplate, DI->getType(), DI, SC, Converted.data(), Converted.size()); + Specialization->setTemplateArgsInfo(TemplateArgs); + + if (!PrevDecl) + VarTemplate->AddSpecialization(Specialization, InsertPos); + } + + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template is + // explicitly specialized then that specialization shall be declared + // before the first use of that specialization that would cause an implicit + // instantiation to take place, in every translation unit in which such a + // use occurs; no diagnostic is required. + if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { + bool Okay = false; + for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) { + Okay = true; + break; + } + } + + if (!Okay) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Name << Range; + + Diag(PrevDecl->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (PrevDecl->getTemplateSpecializationKind() != + TSK_ImplicitInstantiation); + return true; + } + } + + Specialization->setTemplateKeywordLoc(TemplateKWLoc); + Specialization->setLexicalDeclContext(CurContext); + + // Add the specialization into its lexical context, so that it can + // be seen when iterating through the list of declarations in that + // context. However, specializations are not found by name lookup. + CurContext->addDecl(Specialization); + + // Note that this is an explicit specialization. + Specialization->setSpecializationKind(TSK_ExplicitSpecialization); + + if (PrevDecl) { + // Check that this isn't a redefinition of this specialization, + // merging with previous declarations. + LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName, + ForRedeclaration); + PrevSpec.addDecl(PrevDecl); + D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec)); + } + + // Link instantiations of static data members back to the template from + // which they were instantiated. + if (Specialization->isStaticDataMember()) + Specialization->setInstantiationOfStaticDataMember( + VarTemplate->getTemplatedDecl(), + Specialization->getSpecializationKind()); + + return Specialization; +} + +namespace { +/// \brief A partial specialization whose template arguments have matched +/// a given template-id. +struct PartialSpecMatchResult { + VarTemplatePartialSpecializationDecl *Partial; + TemplateArgumentList *Args; +}; +} + +DeclResult +Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, + SourceLocation TemplateNameLoc, + const TemplateArgumentListInfo &TemplateArgs) { + assert(Template && "A variable template id without template?"); + + // Check that the template argument list is well-formed for this template. + SmallVector<TemplateArgument, 4> Converted; + bool ExpansionIntoFixedList = false; + if (CheckTemplateArgumentList( + Template, TemplateNameLoc, + const_cast<TemplateArgumentListInfo &>(TemplateArgs), false, + Converted, &ExpansionIntoFixedList)) + return true; + + // Find the variable template specialization declaration that + // corresponds to these arguments. + void *InsertPos = 0; + if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization( + Converted.data(), Converted.size(), InsertPos)) + // If we already have a variable template specialization, return it. + return Spec; + + // This is the first time we have referenced this variable template + // specialization. Create the canonical declaration and add it to + // the set of specializations, based on the closest partial specialization + // that it represents. That is, + VarDecl *InstantiationPattern = Template->getTemplatedDecl(); + TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + TemplateArgumentList *InstantiationArgs = &TemplateArgList; + bool AmbiguousPartialSpec = false; + typedef PartialSpecMatchResult MatchResult; + SmallVector<MatchResult, 4> Matched; + SourceLocation PointOfInstantiation = TemplateNameLoc; + TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); + + // 1. Attempt to find the closest partial specialization that this + // specializes, if any. + // If any of the template arguments is dependent, then this is probably + // a placeholder for an incomplete declarative context; which must be + // complete by instantiation time. Thus, do not search through the partial + // specializations yet. + // FIXME: Unify with InstantiateClassTemplateSpecialization()? + bool InstantiationDependent = false; + if (!TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, InstantiationDependent)) { + + SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs; + Template->getPartialSpecializations(PartialSpecs); + + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { + VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; + TemplateDeductionInfo Info(FailedCandidates.getLocation()); + + if (TemplateDeductionResult Result = + DeduceTemplateArguments(Partial, TemplateArgList, Info)) { + // Store the failed-deduction information for use in diagnostics, later. + FailedCandidates.addCandidate() + .set(Partial, MakeDeductionFailureInfo(Context, Result, Info)); + (void)Result; + } else { + Matched.push_back(PartialSpecMatchResult()); + Matched.back().Partial = Partial; + Matched.back().Args = Info.take(); + } + } + + // If we're dealing with a member template where the template parameters + // have been instantiated, this provides the original template parameters + // from which the member template's parameters were instantiated. + SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters; + + if (Matched.size() >= 1) { + SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); + if (Matched.size() == 1) { + // -- If exactly one matching specialization is found, the + // instantiation is generated from that specialization. + // We don't need to do anything for this. + } else { + // -- If more than one matching specialization is found, the + // partial order rules (14.5.4.2) are used to determine + // whether one of the specializations is more specialized + // than the others. If none of the specializations is more + // specialized than all of the other matching + // specializations, then the use of the variable template is + // ambiguous and the program is ill-formed. + for (SmallVector<MatchResult, 4>::iterator P = Best + 1, + PEnd = Matched.end(); + P != PEnd; ++P) { + if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, + PointOfInstantiation) == + P->Partial) + Best = P; + } + + // Determine if the best partial specialization is more specialized than + // the others. + for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) { + if (P != Best && getMoreSpecializedPartialSpecialization( + P->Partial, Best->Partial, + PointOfInstantiation) != Best->Partial) { + AmbiguousPartialSpec = true; + break; + } + } + } + + // Instantiate using the best variable template partial specialization. + InstantiationPattern = Best->Partial; + InstantiationArgs = Best->Args; + } else { + // -- If no match is found, the instantiation is generated + // from the primary template. + // InstantiationPattern = Template->getTemplatedDecl(); + } + } + + // FIXME: Actually use FailedCandidates. + + // 2. Create the canonical declaration. + // Note that we do not instantiate the variable just yet, since + // instantiation is handled in DoMarkVarDeclReferenced(). + // FIXME: LateAttrs et al.? + VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation( + Template, InstantiationPattern, *InstantiationArgs, TemplateArgs, + Converted, TemplateNameLoc, InsertPos /*, LateAttrs, StartingScope*/); + if (!Decl) + return true; + + if (AmbiguousPartialSpec) { + // Partial ordering did not produce a clear winner. Complain. + Decl->setInvalidDecl(); + Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) + << Decl; + + // Print the matching partial specializations. + for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) + Diag(P->Partial->getLocation(), diag::note_partial_spec_match) + << getTemplateArgumentBindingsText( + P->Partial->getTemplateParameters(), *P->Args); + return true; + } + + if (VarTemplatePartialSpecializationDecl *D = + dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern)) + Decl->setInstantiationOf(D, InstantiationArgs); + + assert(Decl && "No variable template specialization?"); + return Decl; +} + +ExprResult +Sema::CheckVarTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + VarTemplateDecl *Template, SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs) { + + DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(), + *TemplateArgs); + if (Decl.isInvalid()) + return ExprError(); + + VarDecl *Var = cast<VarDecl>(Decl.get()); + if (!Var->getTemplateSpecializationKind()) + Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, + NameInfo.getLoc()); + + // Build an ordinary singleton decl ref. + return BuildDeclarationNameExpr(SS, NameInfo, Var, + /*FoundD=*/0, TemplateArgs); +} + ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -2282,6 +2735,13 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, assert(!R.empty() && "empty lookup results when building templateid"); assert(!R.isAmbiguous() && "ambiguous lookup when building templateid"); + // In C++1y, check variable template ids. + if (R.getAsSingle<VarTemplateDecl>()) { + return Owned(CheckVarTemplateId(SS, R.getLookupNameInfo(), + R.getAsSingle<VarTemplateDecl>(), + TemplateKWLoc, TemplateArgs)); + } + // We don't want lookup warnings at this point. R.suppressDiagnostics(); @@ -2302,6 +2762,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { + assert(TemplateArgs || TemplateKWLoc.isValid()); DeclContext *DC; if (!(DC = computeDeclContext(SS, false)) || @@ -4962,16 +5423,18 @@ static bool CheckTemplateSpecializationScope(Sema &S, int EntityKind = 0; if (isa<ClassTemplateDecl>(Specialized)) EntityKind = IsPartialSpecialization? 1 : 0; + else if (isa<VarTemplateDecl>(Specialized)) + EntityKind = IsPartialSpecialization ? 3 : 2; else if (isa<FunctionTemplateDecl>(Specialized)) - EntityKind = 2; + EntityKind = 4; else if (isa<CXXMethodDecl>(Specialized)) - EntityKind = 3; + EntityKind = 5; else if (isa<VarDecl>(Specialized)) - EntityKind = 4; + EntityKind = 6; else if (isa<RecordDecl>(Specialized)) - EntityKind = 5; + EntityKind = 7; else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus11) - EntityKind = 6; + EntityKind = 8; else { S.Diag(Loc, diag::err_template_spec_unknown_kind) << S.getLangOpts().CPlusPlus11; @@ -5095,17 +5558,15 @@ static bool CheckTemplateSpecializationScope(Sema &S, return false; } -/// \brief Subroutine of Sema::CheckClassTemplatePartialSpecializationArgs +/// \brief Subroutine of Sema::CheckTemplatePartialSpecializationArgs /// that checks non-type template partial specialization arguments. -static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, - NonTypeTemplateParmDecl *Param, - const TemplateArgument *Args, - unsigned NumArgs) { +static bool CheckNonTypeTemplatePartialSpecializationArgs( + Sema &S, NonTypeTemplateParmDecl *Param, const TemplateArgument *Args, + unsigned NumArgs) { for (unsigned I = 0; I != NumArgs; ++I) { if (Args[I].getKind() == TemplateArgument::Pack) { - if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, - Args[I].pack_begin(), - Args[I].pack_size())) + if (CheckNonTypeTemplatePartialSpecializationArgs( + S, Param, Args[I].pack_begin(), Args[I].pack_size())) return true; continue; @@ -5176,9 +5637,9 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, /// partial specialization. /// /// \returns true if there was an error, false otherwise. -static bool CheckClassTemplatePartialSpecializationArgs(Sema &S, - TemplateParameterList *TemplateParams, - SmallVectorImpl<TemplateArgument> &TemplateArgs) { +static bool CheckTemplatePartialSpecializationArgs( + Sema &S, TemplateParameterList *TemplateParams, + SmallVectorImpl<TemplateArgument> &TemplateArgs) { const TemplateArgument *ArgList = TemplateArgs.data(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { @@ -5187,8 +5648,7 @@ static bool CheckClassTemplatePartialSpecializationArgs(Sema &S, if (!Param) continue; - if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, - &ArgList[I], 1)) + if (CheckNonTypeTemplatePartialSpecializationArgs(S, Param, &ArgList[I], 1)) return true; } @@ -5334,9 +5794,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Find the class template (partial) specialization declaration that // corresponds to these arguments. if (isPartialSpecialization) { - if (CheckClassTemplatePartialSpecializationArgs(*this, - ClassTemplate->getTemplateParameters(), - Converted)) + if (CheckTemplatePartialSpecializationArgs( + *this, ClassTemplate->getTemplateParameters(), Converted)) return true; bool InstantiationDependent; @@ -6207,9 +6666,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { InstantiationVar->setLocation(Member->getLocation()); } - Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member), - cast<VarDecl>(InstantiatedFrom), - TSK_ExplicitSpecialization); + cast<VarDecl>(Member)->setInstantiationOfStaticDataMember( + cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(InstantiationVar); } else if (isa<CXXRecordDecl>(Member)) { CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation); @@ -6697,7 +7155,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::err_explicit_instantiation_inline : diag::warn_explicit_instantiation_inline_0x) << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); - if (D.getDeclSpec().isConstexprSpecified()) + if (D.getDeclSpec().isConstexprSpecified() && R->isFunctionType()) // FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is // not already specified. Diag(D.getDeclSpec().getConstexprSpecLoc(), @@ -6719,28 +7177,68 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // A [...] static data member of a class template can be explicitly // instantiated from the member definition associated with its class // template. + // C++1y [temp.explicit]p1: + // A [...] variable [...] template specialization can be explicitly + // instantiated from its template. if (Previous.isAmbiguous()) return true; VarDecl *Prev = Previous.getAsSingle<VarDecl>(); - if (!Prev || !Prev->isStaticDataMember()) { - // We expect to see a data data member here. - Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) - << Name; - for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); - P != PEnd; ++P) - Diag((*P)->getLocation(), diag::note_explicit_instantiation_here); - return true; - } + VarTemplateDecl *PrevTemplate = Previous.getAsSingle<VarTemplateDecl>(); + + if (!PrevTemplate) { + if (!Prev || !Prev->isStaticDataMember()) { + // We expect to see a data data member here. + Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) + << Name; + for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); + P != PEnd; ++P) + Diag((*P)->getLocation(), diag::note_explicit_instantiation_here); + return true; + } - if (!Prev->getInstantiatedFromStaticDataMember()) { - // FIXME: Check for explicit specialization? - Diag(D.getIdentifierLoc(), - diag::err_explicit_instantiation_data_member_not_instantiated) - << Prev; - Diag(Prev->getLocation(), diag::note_explicit_instantiation_here); - // FIXME: Can we provide a note showing where this was declared? - return true; + if (!Prev->getInstantiatedFromStaticDataMember()) { + // FIXME: Check for explicit specialization? + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_data_member_not_instantiated) + << Prev; + Diag(Prev->getLocation(), diag::note_explicit_instantiation_here); + // FIXME: Can we provide a note showing where this was declared? + return true; + } + } else { + // Explicitly instantiate a variable template. + + // C++1y [dcl.spec.auto]p6: + // ... A program that uses auto or decltype(auto) in a context not + // explicitly allowed in this section is ill-formed. + // + // This includes auto-typed variable template instantiations. + if (R->isUndeducedType()) { + Diag(T->getTypeLoc().getLocStart(), + diag::err_auto_not_allowed_var_inst); + return true; + } + + TemplateArgumentListInfo TemplateArgs; + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + // Translate the parser's template argument list into our AST format. + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + } + + DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc, + D.getIdentifierLoc(), TemplateArgs); + if (Res.isInvalid()) + return true; + + // Ignore access control bits, we don't need them for redeclaration + // checking. + Prev = cast<VarDecl>(Res.get()); } // C++0x [temp.explicit]p2: @@ -6750,7 +7248,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // name shall be a simple-template-id. // // C++98 has the same restriction, just worded differently. - if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) + // + // C++1y If the explicit instantiation is for a variable, the + // unqualified-id in the declaration shall be a template-id. + if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()) && + (!PrevTemplate || + (D.getName().getKind() != UnqualifiedId::IK_TemplateId && + D.getCXXScopeSpec().isSet()))) Diag(D.getIdentifierLoc(), diag::ext_explicit_instantiation_without_qualified_id) << Prev << D.getCXXScopeSpec().getRange(); @@ -6760,20 +7264,39 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Verify that it is okay to explicitly instantiate here. MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); - assert(MSInfo && "Missing static data member specialization info?"); + TemplateSpecializationKind PrevTSK = + MSInfo ? MSInfo->getTemplateSpecializationKind() + : Prev->getTemplateSpecializationKind(); + SourceLocation POI = MSInfo ? MSInfo->getPointOfInstantiation() + : cast<VarTemplateSpecializationDecl>(Prev) + ->getPointOfInstantiation(); bool HasNoEffect = false; if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev, - MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), - HasNoEffect)) + PrevTSK, POI, HasNoEffect)) return true; - if (HasNoEffect) - return (Decl*) 0; - // Instantiate static data member. - Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); - if (TSK == TSK_ExplicitInstantiationDefinition) - InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev); + if (!HasNoEffect) { + // Instantiate static data member or variable template. + + Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); + if (PrevTemplate) { + // Merge attributes. + if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList()) + ProcessDeclAttributeList(S, Prev, Attr); + } + if (TSK == TSK_ExplicitInstantiationDefinition) + InstantiateVariableDefinition(D.getIdentifierLoc(), Prev); + } + + // Check the new variable specialization against the parsed input. + if (PrevTemplate && Prev && !Context.hasSameType(Prev->getType(), R)) { + Diag(T->getTypeLoc().getLocStart(), + diag::err_invalid_var_template_spec_type) + << 0 << PrevTemplate << R << Prev->getType(); + Diag(PrevTemplate->getLocation(), diag::note_template_declared_here) + << 2 << PrevTemplate->getDeclName(); + return true; + } // FIXME: Create an ExplicitInstantiation node? return (Decl*) 0; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 8d6aaa096df..e87354663b0 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2246,7 +2246,7 @@ FinishTemplateArgumentDeduction(Sema &S, } /// \brief Perform template argument deduction to determine whether -/// the given template arguments match the given class template +/// the given template arguments match the given variable template /// partial specialization per C++ [temp.class.spec.match]. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, @@ -2287,6 +2287,160 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Deduced, Info); } +/// Complete template argument deduction for a variable template partial +/// specialization. +/// TODO: Unify with ClassTemplatePartialSpecializationDecl version. +static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( + Sema &S, VarTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + TemplateDeductionInfo &Info) { + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); + Sema::SFINAETrap Trap(S); + + // C++ [temp.deduct.type]p2: + // [...] or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + SmallVector<TemplateArgument, 4> Builder; + TemplateParameterList *PartialParams = Partial->getTemplateParameters(); + for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) { + NamedDecl *Param = PartialParams->getParam(I); + if (Deduced[I].isNull()) { + Info.Param = makeTemplateParameter(Param); + return Sema::TDK_Incomplete; + } + + // We have deduced this argument, so it still needs to be + // checked and converted. + + // First, for a non-type template parameter type that is + // initialized by a declaration, we need the type of the + // corresponding non-type template parameter. + QualType NTTPType; + if (NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(Param)) { + NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Builder.data(), Builder.size()); + NTTPType = + S.SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), NTTP->getDeclName()); + if (NTTPType.isNull()) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + Builder.size())); + return Sema::TDK_SubstitutionFailure; + } + } + } + + if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial, NTTPType, + 0, Info, false, Builder)) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + Builder.size())); + return Sema::TDK_SubstitutionFailure; + } + } + + // Form the template argument list from the deduced template arguments. + TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy( + S.Context, Builder.data(), Builder.size()); + + Info.reset(DeducedArgumentList); + + // Substitute the deduced template arguments into the template + // arguments of the class template partial specialization, and + // verify that the instantiated template arguments are both valid + // and are equivalent to the template arguments originally provided + // to the class template. + LocalInstantiationScope InstScope(S); + VarTemplateDecl *VarTemplate = Partial->getSpecializedTemplate(); + const TemplateArgumentLoc *PartialTemplateArgs = + Partial->getTemplateArgsAsWritten(); + + // Note that we don't provide the langle and rangle locations. + TemplateArgumentListInfo InstArgs; + + if (S.Subst(PartialTemplateArgs, Partial->getNumTemplateArgsAsWritten(), + InstArgs, MultiLevelTemplateArgumentList(*DeducedArgumentList))) { + unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; + if (ParamIdx >= Partial->getTemplateParameters()->size()) + ParamIdx = Partial->getTemplateParameters()->size() - 1; + + Decl *Param = const_cast<NamedDecl *>( + Partial->getTemplateParameters()->getParam(ParamIdx)); + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = PartialTemplateArgs[ArgIdx].getArgument(); + return Sema::TDK_SubstitutionFailure; + } + SmallVector<TemplateArgument, 4> ConvertedInstArgs; + if (S.CheckTemplateArgumentList(VarTemplate, Partial->getLocation(), InstArgs, + false, ConvertedInstArgs)) + return Sema::TDK_SubstitutionFailure; + + TemplateParameterList *TemplateParams = VarTemplate->getTemplateParameters(); + for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { + TemplateArgument InstArg = ConvertedInstArgs.data()[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { + Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); + Info.FirstArg = TemplateArgs[I]; + Info.SecondArg = InstArg; + return Sema::TDK_NonDeducedMismatch; + } + } + + if (Trap.hasErrorOccurred()) + return Sema::TDK_SubstitutionFailure; + + return Sema::TDK_Success; +} + +/// \brief Perform template argument deduction to determine whether +/// the given template arguments match the given variable template +/// partial specialization per C++ [temp.class.spec.match]. +/// TODO: Unify with ClassTemplatePartialSpecializationDecl version. +Sema::TemplateDeductionResult +Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + TemplateDeductionInfo &Info) { + if (Partial->isInvalidDecl()) + return TDK_Invalid; + + // C++ [temp.class.spec.match]p2: + // A partial specialization matches a given actual template + // argument list if the template arguments of the partial + // specialization can be deduced from the actual template argument + // list (14.8.2). + + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); + SFINAETrap Trap(*this); + + SmallVector<DeducedTemplateArgument, 4> Deduced; + Deduced.resize(Partial->getTemplateParameters()->size()); + if (TemplateDeductionResult Result = ::DeduceTemplateArguments( + *this, Partial->getTemplateParameters(), Partial->getTemplateArgs(), + TemplateArgs, Info, Deduced)) + return Result; + + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); + InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, + DeducedArgs, Info); + if (Inst) + return TDK_InstantiationDepth; + + if (Trap.hasErrorOccurred()) + return Sema::TDK_SubstitutionFailure; + + return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, + Deduced, Info); +} + /// \brief Determine whether the given type T is a simple-template-id type. static bool isSimpleTemplateIdType(QualType T) { if (const TemplateSpecializationType *Spec @@ -4278,6 +4432,63 @@ Sema::getMoreSpecializedPartialSpecialization( /*RefParamComparisons=*/0); if (Better1) { SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end()); + InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, DeducedArgs, + Info); + Better1 = !::FinishTemplateArgumentDeduction( + *this, PS2, PS1->getTemplateArgs(), Deduced, Info); + } + + // Determine whether PS2 is at least as specialized as PS1 + Deduced.clear(); + Deduced.resize(PS1->getTemplateParameters()->size()); + bool Better2 = !DeduceTemplateArgumentsByTypeMatch( + *this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None, + /*PartialOrdering=*/true, + /*RefParamComparisons=*/0); + if (Better2) { + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), + Deduced.end()); + InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1, DeducedArgs, + Info); + Better2 = !::FinishTemplateArgumentDeduction( + *this, PS1, PS2->getTemplateArgs(), Deduced, Info); + } + + if (Better1 == Better2) + return 0; + + return Better1 ? PS1 : PS2; +} + +/// TODO: Unify with ClassTemplatePartialSpecializationDecl version. +VarTemplatePartialSpecializationDecl * +Sema::getMoreSpecializedPartialSpecialization( + VarTemplatePartialSpecializationDecl *PS1, + VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) { + SmallVector<DeducedTemplateArgument, 4> Deduced; + TemplateDeductionInfo Info(Loc); + + assert(PS1->getSpecializedTemplate() == PS1->getSpecializedTemplate() && + "the partial specializations being compared should specialize" + " the same template."); + TemplateName Name(PS1->getSpecializedTemplate()); + TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); + QualType PT1 = Context.getTemplateSpecializationType( + CanonTemplate, PS1->getTemplateArgs().data(), + PS1->getTemplateArgs().size()); + QualType PT2 = Context.getTemplateSpecializationType( + CanonTemplate, PS2->getTemplateArgs().data(), + PS2->getTemplateArgs().size()); + + // Determine whether PS1 is at least as specialized as PS2 + Deduced.resize(PS2->getTemplateParameters()->size()); + bool Better1 = !DeduceTemplateArgumentsByTypeMatch( + *this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None, + /*PartialOrdering=*/true, + /*RefParamComparisons=*/0); + if (Better1) { + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), + Deduced.end()); InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, DeducedArgs, Info); Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 57eb64d127a..25eb72ce1cb 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -61,7 +61,24 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, DeclContext *Ctx = dyn_cast<DeclContext>(D); if (!Ctx) { Ctx = D->getDeclContext(); - + + // Add template arguments from a variable template instantiation. + if (VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(D)) { + // We're done when we hit an explicit specialization. + if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa<VarTemplatePartialSpecializationDecl>(Spec)) + return Result; + + Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); + + // If this variable template specialization was instantiated from a + // specialized member that is a variable template, we're done. + assert(Spec->getSpecializedTemplate() && "No variable template?"); + if (Spec->getSpecializedTemplate()->isMemberSpecialization()) + return Result; + } + // If we have a template template parameter with translation unit context, // then we're performing substitution into a default template argument of // this template template parameter before we've constructed the template @@ -292,6 +309,29 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, } } +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + VarTemplatePartialSpecializationDecl *PartialSpec, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + : SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) { + Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = PartialSpec; + Inst.TemplateArgs = TemplateArgs.data(); + Inst.NumTemplateArgs = TemplateArgs.size(); + Inst.DeductionInfo = &DeductionInfo; + Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + } +} + Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 52075229971..b93fe9a966a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -318,7 +318,13 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { return Inst; } +// FIXME: Revise for static member templates. Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { + return VisitVarDecl(D, /*ForVarTemplate=*/false); +} + +Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, bool ForVarTemplate) { + // If this is the variable for an anonymous struct or union, // instantiate the anonymous struct/union type first. if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) @@ -340,105 +346,22 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { return 0; } - // Build the instantiated declaration - VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, - D->getInnerLocStart(), + // Build the instantiated declaration. + VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), D->getIdentifier(), - DI->getType(), DI, - D->getStorageClass()); - Var->setTSCSpec(D->getTSCSpec()); - Var->setInitStyle(D->getInitStyle()); - Var->setCXXForRangeDecl(D->isCXXForRangeDecl()); - Var->setConstexpr(D->isConstexpr()); + DI->getType(), DI, D->getStorageClass()); - // Substitute the nested name specifier, if any. - if (SubstQualifier(D, Var)) - return 0; - - // If we are instantiating a static data member defined - // out-of-line, the instantiation will have the same lexical - // context (which will be a namespace scope) as the template. - if (D->isOutOfLine()) - Var->setLexicalDeclContext(D->getLexicalDeclContext()); - - Var->setAccess(D->getAccess()); - - if (!D->isStaticDataMember()) { - Var->setUsed(D->isUsed(false)); - Var->setReferenced(D->isReferenced()); - } - - SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope); - - if (Var->hasAttrs()) - SemaRef.CheckAlignasUnderalignment(Var); - - // FIXME: In theory, we could have a previous declaration for variables that - // are not static data members. - // FIXME: having to fake up a LookupResult is dumb. - LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(), - Sema::LookupOrdinaryName, Sema::ForRedeclaration); - if (D->isStaticDataMember()) - SemaRef.LookupQualifiedName(Previous, Owner, false); - // In ARC, infer 'retaining' for variables of retainable type. if (SemaRef.getLangOpts().ObjCAutoRefCount && SemaRef.inferObjCARCLifetime(Var)) Var->setInvalidDecl(); - SemaRef.CheckVariableDeclaration(Var, Previous); - - if (D->isOutOfLine()) { - D->getLexicalDeclContext()->addDecl(Var); - Owner->makeDeclVisibleInContext(Var); - } else { - Owner->addDecl(Var); - if (Owner->isFunctionOrMethod()) - SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var); - } - - // Link instantiations of static data members back to the template from - // which they were instantiated. - if (Var->isStaticDataMember()) - SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, - TSK_ImplicitInstantiation); - - if (Var->getAnyInitializer()) { - // We already have an initializer in the class. - } else if (D->getInit()) { - if (Var->isStaticDataMember() && !D->isOutOfLine()) - SemaRef.PushExpressionEvaluationContext(Sema::ConstantEvaluated, D); - else - SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, D); - - // Instantiate the initializer. - ExprResult Init = SemaRef.SubstInitializer(D->getInit(), TemplateArgs, - D->getInitStyle() == VarDecl::CallInit); - if (!Init.isInvalid()) { - bool TypeMayContainAuto = true; - if (Init.get()) { - bool DirectInit = D->isDirectInit(); - SemaRef.AddInitializerToDecl(Var, Init.take(), DirectInit, - TypeMayContainAuto); - } else - SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto); - } else { - // FIXME: Not too happy about invalidating the declaration - // because of a bogus initializer. - Var->setInvalidDecl(); - } - - SemaRef.PopExpressionEvaluationContext(); - } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) && - !Var->isCXXForRangeDecl()) - SemaRef.ActOnUninitializedDecl(Var, false); - - // Diagnose unused local variables with dependent types, where the diagnostic - // will have been deferred. - if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed() && - D->getType()->isDependentType()) - SemaRef.DiagnoseUnusedDecl(Var); + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Var)) + return 0; + SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, + StartingScope, ForVarTemplate); return Var; } @@ -1026,6 +949,102 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( return InstantiateClassTemplatePartialSpecialization(InstClassTemplate, D); } +Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) { + assert(D->getTemplatedDecl()->isStaticDataMember() && + "Only static data member templates are allowed."); + // FIXME: Also only when instantiating a class? + + // Create a local instantiation scope for this variable template, which + // will contain the instantiations of the template parameters. + LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return NULL; + + VarDecl *Pattern = D->getTemplatedDecl(); + VarTemplateDecl *PrevVarTemplate = 0; + + if (Pattern->getPreviousDecl()) { + DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); + if (!Found.empty()) + PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front()); + } + + // FIXME: This, and ForVarTemplate, is a hack that is probably unnecessary. + // We should use a simplified version of VisitVarDecl. + VarDecl *VarInst = cast_or_null<VarDecl>(VisitVarDecl(Pattern, /*ForVarTemplate=*/true)); + + DeclContext *DC = Owner; + + /* FIXME: This should be handled in VisitVarDecl, as used to produce + VarInst above. + // Instantiate the qualifier. + NestedNameSpecifierLoc QualifierLoc = Pattern->getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = + SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs); + if (!QualifierLoc) + return 0; + } + + if (QualifierLoc) + VarInst->setQualifierInfo(QualifierLoc); + */ + + VarTemplateDecl *Inst = VarTemplateDecl::Create( + SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams, + VarInst, PrevVarTemplate); + VarInst->setDescribedVarTemplate(Inst); + + Inst->setAccess(D->getAccess()); + if (!PrevVarTemplate) + Inst->setInstantiatedFromMemberTemplate(D); + + if (D->isOutOfLine()) { + Inst->setLexicalDeclContext(D->getLexicalDeclContext()); + VarInst->setLexicalDeclContext(D->getLexicalDeclContext()); + } + + Owner->addDecl(Inst); + + if (!PrevVarTemplate) { + // Queue up any out-of-line partial specializations of this member + // variable template; the client will force their instantiation once + // the enclosing class has been instantiated. + SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs; + D->getPartialSpecializations(PartialSpecs); + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) + if (PartialSpecs[I]->isOutOfLine()) + OutOfLineVarPartialSpecs.push_back( + std::make_pair(Inst, PartialSpecs[I])); + } + + return Inst; +} + +Decl *TemplateDeclInstantiator::VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D) { + assert(D->isStaticDataMember() && + "Only static data member templates are allowed."); + // FIXME: Also only when instantiating a class? + + VarTemplateDecl *VarTemplate = D->getSpecializedTemplate(); + + // Lookup the already-instantiated declaration and return that. + DeclContext::lookup_result Found = Owner->lookup(VarTemplate->getDeclName()); + assert(!Found.empty() && "Instantiation found nothing?"); + + VarTemplateDecl *InstVarTemplate = dyn_cast<VarTemplateDecl>(Found.front()); + assert(InstVarTemplate && "Instantiation did not find a variable template?"); + + if (VarTemplatePartialSpecializationDecl *Result = + InstVarTemplate->findPartialSpecInstantiatedFromMember(D)) + return Result; + + return InstantiateVarTemplatePartialSpecialization(InstVarTemplate, D); +} + Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // Create a local instantiation scope for this function template, which @@ -2256,6 +2275,87 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( "inside templates"); } +Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *D) { + + TemplateArgumentListInfo VarTemplateArgsInfo; + VarTemplateDecl *VarTemplate = D->getSpecializedTemplate(); + assert(VarTemplate && + "A template specialization without specialized template?"); + + // Substitute the current template arguments. + const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo(); + VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc()); + VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo.getRAngleLoc()); + + if (SemaRef.Subst(TemplateArgsInfo.getArgumentArray(), + TemplateArgsInfo.size(), VarTemplateArgsInfo, TemplateArgs)) + return 0; + + // Check that the template argument list is well-formed for this template. + SmallVector<TemplateArgument, 4> Converted; + bool ExpansionIntoFixedList = false; + if (SemaRef.CheckTemplateArgumentList( + VarTemplate, VarTemplate->getLocStart(), + const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false, + Converted, &ExpansionIntoFixedList)) + return 0; + + // Find the variable template specialization declaration that + // corresponds to these arguments. + void *InsertPos = 0; + if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization( + Converted.data(), Converted.size(), InsertPos)) + // If we already have a variable template specialization, return it. + return VarSpec; + + return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos, + VarTemplateArgsInfo, Converted); +} + +Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( + VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos, + const TemplateArgumentListInfo &TemplateArgsInfo, + SmallVectorImpl<TemplateArgument> &Converted) { + + // If this is the variable for an anonymous struct or union, + // instantiate the anonymous struct/union type first. + if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) + if (RecordTy->getDecl()->isAnonymousStructOrUnion()) + if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl()))) + return 0; + + // Do substitution on the type of the declaration + TypeSourceInfo *DI = + SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, + D->getTypeSpecStartLoc(), D->getDeclName()); + if (!DI) + return 0; + + if (DI->getType()->isFunctionType()) { + SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function) + << D->isStaticDataMember() << DI->getType(); + return 0; + } + + // Build the instantiated declaration + VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create( + SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), + VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(), + Converted.size()); + Var->setTemplateArgsInfo(TemplateArgsInfo); + VarTemplate->AddSpecialization(Var, InsertPos); + + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Var)) + return 0; + + SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, + StartingScope); + + return Var; +} + Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { llvm_unreachable("@defs is not supported in Objective-C++"); } @@ -2442,6 +2542,134 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( return InstPartialSpec; } +/// \brief Instantiate the declaration of a variable template partial +/// specialization. +/// +/// \param VarTemplate the (instantiated) variable template that is partially +/// specialized by the instantiation of \p PartialSpec. +/// +/// \param PartialSpec the (uninstantiated) variable template partial +/// specialization that we are instantiating. +/// +/// \returns The instantiated partial specialization, if successful; otherwise, +/// NULL to indicate an error. +VarTemplatePartialSpecializationDecl * +TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( + VarTemplateDecl *VarTemplate, + VarTemplatePartialSpecializationDecl *PartialSpec) { + // Create a local instantiation scope for this variable template partial + // specialization, which will contain the instantiations of the template + // parameters. + LocalInstantiationScope Scope(SemaRef); + + // Substitute into the template parameters of the variable template partial + // specialization. + TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return 0; + + // Substitute into the template arguments of the variable template partial + // specialization. + TemplateArgumentListInfo InstTemplateArgs; // no angle locations + if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(), + PartialSpec->getNumTemplateArgsAsWritten(), + InstTemplateArgs, TemplateArgs)) + return 0; + + // Check that the template argument list is well-formed for this + // class template. + SmallVector<TemplateArgument, 4> Converted; + if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(), + InstTemplateArgs, false, Converted)) + return 0; + + // Figure out where to insert this variable template partial specialization + // in the member template's set of variable template partial specializations. + void *InsertPos = 0; + VarTemplateSpecializationDecl *PrevDecl = + VarTemplate->findPartialSpecialization(Converted.data(), Converted.size(), + InsertPos); + + // Build the canonical type that describes the converted template + // arguments of the variable template partial specialization. + QualType CanonType = SemaRef.Context.getTemplateSpecializationType( + TemplateName(VarTemplate), Converted.data(), Converted.size()); + + // Build the fully-sugared type for this variable 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(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs, + CanonType); + + if (PrevDecl) { + // We've already seen a partial specialization with the same template + // parameters and template arguments. This can happen, for example, when + // substituting the outer template arguments ends up causing two + // variable template partial specializations of a member variable template + // to have identical forms, e.g., + // + // template<typename T, typename U> + // struct Outer { + // template<typename X, typename Y> pair<X,Y> p; + // template<typename Y> pair<T, Y> p; + // template<typename Y> pair<U, Y> p; + // }; + // + // Outer<int, int> outer; // error: the partial specializations of Inner + // // have the same signature. + SemaRef.Diag(PartialSpec->getLocation(), + diag::err_var_partial_spec_redeclared) + << WrittenTy->getType(); + SemaRef.Diag(PrevDecl->getLocation(), + diag::note_var_prev_partial_spec_here); + return 0; + } + + // Do substitution on the type of the declaration + TypeSourceInfo *DI = SemaRef.SubstType( + PartialSpec->getTypeSourceInfo(), TemplateArgs, + PartialSpec->getTypeSpecStartLoc(), PartialSpec->getDeclName()); + if (!DI) + return 0; + + if (DI->getType()->isFunctionType()) { + SemaRef.Diag(PartialSpec->getLocation(), + diag::err_variable_instantiates_to_function) + << PartialSpec->isStaticDataMember() << DI->getType(); + return 0; + } + + // Create the variable template partial specialization declaration. + VarTemplatePartialSpecializationDecl *InstPartialSpec = + VarTemplatePartialSpecializationDecl::Create( + SemaRef.Context, Owner, PartialSpec->getInnerLocStart(), + PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(), + DI, PartialSpec->getStorageClass(), Converted.data(), + Converted.size(), InstTemplateArgs, + VarTemplate->getNextPartialSpecSequenceNumber()); + + // Substitute the nested name specifier, if any. + if (SubstQualifier(PartialSpec, InstPartialSpec)) + return 0; + + InstPartialSpec->setInstantiatedFromMember(PartialSpec); + InstPartialSpec->setTypeAsWritten(WrittenTy); + + InstPartialSpec->setAccess(PartialSpec->getAccess()); + // FIXME: How much of BuildVariableInstantiation() should go in here? + + // Add this partial specialization to the set of variable template partial + // specializations. The instantiation of the initializer is not necessary. + VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0); + return InstPartialSpec; +} + TypeSourceInfo* TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, SmallVectorImpl<ParmVarDecl *> &Params) { @@ -3026,6 +3254,167 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, PendingLocalImplicitInstantiations); } +VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( + VarTemplateDecl *VarTemplate, VarDecl *FromVar, + const TemplateArgumentList &TemplateArgList, + const TemplateArgumentListInfo &TemplateArgsInfo, + SmallVectorImpl<TemplateArgument> &Converted, + SourceLocation PointOfInstantiation, void *InsertPos, + LateInstantiatedAttrVec *LateAttrs, + LocalInstantiationScope *StartingScope) { + if (FromVar->isInvalidDecl()) + return 0; + + InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar); + if (Inst) + return 0; + + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(&TemplateArgList); + + TemplateDeclInstantiator Instantiator( + *this, VarTemplate->getDeclContext(), + MultiLevelTemplateArgumentList(TemplateArgList)); + + // TODO: Set LateAttrs and StartingScope ... + + return cast_or_null<VarTemplateSpecializationDecl>( + Instantiator.VisitVarTemplateSpecializationDecl( + VarTemplate, FromVar, InsertPos, TemplateArgsInfo, Converted)); +} + +/// \brief Instantiates a variable template specialization by completing it +/// with appropriate type information and initializer. +VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, + const MultiLevelTemplateArgumentList &TemplateArgs) { + + // Do substitution on the type of the declaration + TypeSourceInfo *DI = + SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs, + PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName()); + if (!DI) + return 0; + + // Update the type of this variable template specialization. + VarSpec->setType(DI->getType()); + + // Instantiate the initializer. + InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs); + + return VarSpec; +} + +/// BuildVariableInstantiation - Used after a new variable has been created. +/// Sets basic variable data and decides whether to postpone the +/// variable instantiation. +void Sema::BuildVariableInstantiation( + VarDecl *NewVar, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs, + LateInstantiatedAttrVec *LateAttrs, + LocalInstantiationScope *StartingScope, + bool ForVarTemplate) { + + // If we are instantiating a static data member defined + // out-of-line, the instantiation will have the same lexical + // context (which will be a namespace scope) as the template. + if (OldVar->isOutOfLine()) + NewVar->setLexicalDeclContext(OldVar->getLexicalDeclContext()); + NewVar->setTSCSpec(OldVar->getTSCSpec()); + NewVar->setInitStyle(OldVar->getInitStyle()); + NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl()); + NewVar->setConstexpr(OldVar->isConstexpr()); + NewVar->setAccess(OldVar->getAccess()); + + if (!OldVar->isStaticDataMember()) { + NewVar->setUsed(OldVar->isUsed(false)); + NewVar->setReferenced(OldVar->isReferenced()); + } + + InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope); + + if (NewVar->hasAttrs()) + CheckAlignasUnderalignment(NewVar); + + // FIXME: In theory, we could have a previous declaration for variables that + // are not static data members. + // FIXME: having to fake up a LookupResult is dumb. + LookupResult Previous(*this, NewVar->getDeclName(), NewVar->getLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + + if (!isa<VarTemplateSpecializationDecl>(NewVar)) + LookupQualifiedName(Previous, NewVar->getDeclContext(), false); + + CheckVariableDeclaration(NewVar, Previous); + + if (OldVar->isOutOfLine()) { + OldVar->getLexicalDeclContext()->addDecl(NewVar); + if (!ForVarTemplate) + NewVar->getDeclContext()->makeDeclVisibleInContext(NewVar); + } else { + if (!ForVarTemplate) + NewVar->getDeclContext()->addDecl(NewVar); + if (NewVar->getDeclContext()->isFunctionOrMethod()) + CurrentInstantiationScope->InstantiatedLocal(OldVar, NewVar); + } + + // Link instantiations of static data members back to the template from + // which they were instantiated. + if (NewVar->isStaticDataMember() && !ForVarTemplate) + NewVar->setInstantiationOfStaticDataMember(OldVar, + TSK_ImplicitInstantiation); + + if (isa<VarTemplateSpecializationDecl>(NewVar)) { + // Do not instantiate the variable just yet. + } else + InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); + + // Diagnose unused local variables with dependent types, where the diagnostic + // will have been deferred. + if (!NewVar->isInvalidDecl() && + NewVar->getDeclContext()->isFunctionOrMethod() && !NewVar->isUsed() && + OldVar->getType()->isDependentType()) + DiagnoseUnusedDecl(NewVar); +} + +/// \brief Instantiate the initializer of a variable. +void Sema::InstantiateVariableInitializer( + VarDecl *Var, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs) { + + if (Var->getAnyInitializer()) + // We already have an initializer in the class. + return; + + if (OldVar->getInit()) { + if (Var->isStaticDataMember() && !OldVar->isOutOfLine()) + PushExpressionEvaluationContext(Sema::ConstantEvaluated, OldVar); + else + PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar); + + // Instantiate the initializer. + ExprResult Init = + SubstInitializer(OldVar->getInit(), TemplateArgs, + OldVar->getInitStyle() == VarDecl::CallInit); + if (!Init.isInvalid()) { + bool TypeMayContainAuto = true; + if (Init.get()) { + bool DirectInit = OldVar->isDirectInit(); + AddInitializerToDecl(Var, Init.take(), DirectInit, TypeMayContainAuto); + } else + ActOnUninitializedDecl(Var, TypeMayContainAuto); + } else { + // FIXME: Not too happy about invalidating the declaration + // because of a bogus initializer. + Var->setInvalidDecl(); + } + + PopExpressionEvaluationContext(); + } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) && + !Var->isCXXForRangeDecl()) + ActOnUninitializedDecl(Var, false); +} + /// \brief Instantiate the definition of the given variable from its /// template. /// @@ -3047,26 +3436,76 @@ void Sema::InstantiateStaticDataMemberDefinition( VarDecl *Var, bool Recursive, bool DefinitionRequired) { + InstantiateVariableDefinition(PointOfInstantiation, Var, Recursive, + DefinitionRequired); +} + +void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, + VarDecl *Var, bool Recursive, + bool DefinitionRequired) { + if (Var->isInvalidDecl()) return; - // Find the out-of-line definition of this static data member. + VarTemplateSpecializationDecl *VarSpec = + dyn_cast<VarTemplateSpecializationDecl>(Var); + assert((VarSpec || Var->isStaticDataMember()) && + "Not a static data member, nor a variable template specialization?"); + VarDecl *PatternDecl = 0; + + // If this is a variable template specialization, make sure that it is + // non-dependent, then find its instantiation pattern. + if (VarSpec) { + bool InstantiationDependent = false; + assert(!TemplateSpecializationType::anyDependentTemplateArguments( + VarSpec->getTemplateArgsInfo(), InstantiationDependent) && + "Only instantiate variable template specializations that are " + "not type-dependent"); + + // Find the variable initialization that we'll be substituting. + assert(VarSpec->getSpecializedTemplate() && + "Specialization without specialized template?"); + llvm::PointerUnion<VarTemplateDecl *, + VarTemplatePartialSpecializationDecl *> PatternPtr = + VarSpec->getSpecializedTemplateOrPartial(); + if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) + PatternDecl = cast<VarDecl>( + PatternPtr.get<VarTemplatePartialSpecializationDecl *>()); + else + PatternDecl = (PatternPtr.get<VarTemplateDecl *>())->getTemplatedDecl(); + assert(PatternDecl && "instantiating a non-template"); + } + + // If this is a static data member, find its out-of-line definition. VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); - assert(Def && "This data member was not instantiated from a template?"); - assert(Def->isStaticDataMember() && "Not a static data member?"); - Def = Def->getOutOfLineDefinition(); - - if (!Def) { - // We did not find an out-of-line definition of this static data member, - // so we won't perform any instantiation. Rather, we rely on the user to - // instantiate this definition (or provide a specialization for it) in - // another translation unit. + if (Var->isStaticDataMember()) { + assert(Def && "This data member was not instantiated from a template?"); + assert(Def->isStaticDataMember() && "Not a static data member?"); + Def = Def->getOutOfLineDefinition(); + } + + // If the instantiation pattern does not have an initializer, or if an + // out-of-line definition is not found, we won't perform any instantiation. + // Rather, we rely on the user to instantiate this definition (or provide + // a specialization for it) in another translation unit. + if ((VarSpec && !PatternDecl->getInit()) || + (!VarSpec && Var->isStaticDataMember() && !Def)) { if (DefinitionRequired) { - Def = Var->getInstantiatedFromStaticDataMember(); - Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_member) - << 2 << Var->getDeclName() << Var->getDeclContext(); - Diag(Def->getLocation(), diag::note_explicit_instantiation_here); + if (!Var->isStaticDataMember()) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_var_template) + << PatternDecl; + Diag(PatternDecl->getLocation(), + diag::note_explicit_instantiation_here); + } else { + Def = Var->getInstantiatedFromStaticDataMember(); + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 3 << Var->getDeclName() << Var->getDeclContext(); + Diag(Def->getLocation(), diag::note_explicit_instantiation_here); + } + if (VarSpec) + Var->setInvalidDecl(); } else if (Var->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition) { PendingInstantiations.push_back( @@ -3086,6 +3525,11 @@ void Sema::InstantiateStaticDataMemberDefinition( // Except for inline functions, other explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity // to which they refer. + // + // C++11 [temp.explicit]p10: + // Except for inline functions, [...] explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. if (TSK == TSK_ExplicitInstantiationDeclaration) return; @@ -3098,17 +3542,24 @@ void Sema::InstantiateStaticDataMemberDefinition( : Consumer(Consumer), Var(Var) { } ~PassToConsumerRAII() { - Consumer.HandleCXXStaticMemberVarInstantiation(Var); + if (Var->isStaticDataMember()) + Consumer.HandleCXXStaticMemberVarInstantiation(Var); + else { + DeclGroupRef DG(Var); + Consumer.HandleTopLevelDecl(DG); + } } } PassToConsumerRAII(Consumer, Var); - // If we already have a definition, we're done. - if (VarDecl *Def = Var->getDefinition()) { - // We may be explicitly instantiating something we've already implicitly - // instantiated. - Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(), - PointOfInstantiation); - return; + if (!VarSpec) { + // If we already have a definition, we're done. + if (VarDecl *Def = Var->getDefinition()) { + // We may be explicitly instantiating something we've already implicitly + // instantiated. + Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(), + PointOfInstantiation); + return; + } } InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); @@ -3127,22 +3578,41 @@ void Sema::InstantiateStaticDataMemberDefinition( // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. - ContextRAII previousContext(*this, Var->getDeclContext()); + ContextRAII PreviousContext(*this, Var->getDeclContext()); LocalInstantiationScope Local(*this); - + VarDecl *OldVar = Var; - Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), - getTemplateInstantiationArgs(Var))); + if (!VarSpec) + Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), + getTemplateInstantiationArgs(Var))); + else + // Construct a VarTemplateSpecializationDecl to avoid name clashing with + // the primary template. (Note that unlike function declarations, variable + // declarations cannot be overloaded.) + // In fact, there is no need to construct a new declaration from scratch. + // Thus, simply complete its definition with an appropriately substituted + // type and initializer. + Var = CompleteVarTemplateSpecializationDecl( + VarSpec, PatternDecl, getTemplateInstantiationArgs(Var)); - previousContext.pop(); + PreviousContext.pop(); if (Var) { - PassToConsumerRAII.Var = Var; MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo(); - assert(MSInfo && "Missing member specialization information?"); - Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation()); + if (!VarSpec) + assert(MSInfo && "Missing member specialization information?"); + + PassToConsumerRAII.Var = Var; + if (MSInfo) + Var->setTemplateSpecializationKind( + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation()); } + + // This variable may have local implicit instantiations that need to be + // instantiated within this scope. + PerformPendingInstantiations(/*LocalOnly=*/true); + Local.Exit(); if (Recursive) { @@ -3155,14 +3625,12 @@ void Sema::InstantiateStaticDataMemberDefinition( // Restore the set of pending vtables. assert(VTableUses.empty() && - "VTableUses should be empty before it is discarded, " - "while instantiating static data member."); + "VTableUses should be empty before it is discarded."); VTableUses.swap(SavedVTableUses); // Restore the set of pending implicit instantiations. assert(PendingInstantiations.empty() && - "PendingInstantiations should be empty before it is discarded, " - "while instantiating static data member."); + "PendingInstantiations should be empty before it is discarded."); PendingInstantiations.swap(SavedPendingInstantiations); } } @@ -3593,6 +4061,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, return cast<LabelDecl>(Inst); } + // For variable template specializations, update those that are still + // type-dependent. + if (VarTemplateSpecializationDecl *VarSpec = + dyn_cast<VarTemplateSpecializationDecl>(D)) { + bool InstantiationDependent = false; + const TemplateArgumentListInfo &VarTemplateArgs = + VarSpec->getTemplateArgsInfo(); + if (TemplateSpecializationType::anyDependentTemplateArguments( + VarTemplateArgs, InstantiationDependent)) + D = cast<NamedDecl>( + SubstDecl(D, VarSpec->getDeclContext(), TemplateArgs)); + return D; + } + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { if (!Record->isDependentContext()) return D; @@ -3605,7 +4087,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, else if (ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) ClassTemplate = PartialSpec->getSpecializedTemplate()->getCanonicalDecl(); - + // Walk the current context to find either the record or an instantiation of // it. DeclContext *DC = CurContext; @@ -3614,7 +4096,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // definition, we'll find our own context. We're done. if (DC->Equals(Record)) return Record; - + if (CXXRecordDecl *InstRecord = dyn_cast<CXXRecordDecl>(DC)) { // Check whether we're in the process of instantiating a class template // specialization of the template we're mapping. @@ -3624,13 +4106,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (ClassTemplate && isInstantiationOf(ClassTemplate, SpecTemplate)) return InstRecord; } - + // Check whether we're in the process of instantiating a member class. if (isInstantiationOf(Record, InstRecord)) return InstRecord; } - - + // Move to the outer template scope. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) { if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){ @@ -3638,7 +4119,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, continue; } } - + DC = DC->getParent(); } @@ -3771,9 +4252,13 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { continue; } - // Instantiate static data member definitions. + // Instantiate variable definitions VarDecl *Var = cast<VarDecl>(Inst.first); - assert(Var->isStaticDataMember() && "Not a static data member?"); + + assert((Var->isStaticDataMember() || + isa<VarTemplateSpecializationDecl>(Var)) && + "Not a static data member, nor a variable template" + " specialization?"); // Don't try to instantiate declarations if the most recent redeclaration // is invalid. @@ -3796,14 +4281,15 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { break; } - PrettyDeclStackTraceEntry CrashInfo(*this, Var, Var->getLocation(), - "instantiating static data member " - "definition"); - + PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + "instantiating variable definition"); bool DefinitionRequired = Var->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition; - InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true, - DefinitionRequired); + + // Instantiate static data member definitions or variable template + // specializations. + InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true, + DefinitionRequired); } } diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 24b268f36df..79bba0cb94f 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -158,6 +158,8 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::CXXRecord: case Decl::ClassTemplateSpecialization: case Decl::ClassTemplatePartialSpecialization: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: case Decl::Function: case Decl::CXXMethod: case Decl::CXXConstructor: @@ -166,6 +168,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::Var: case Decl::FunctionTemplate: case Decl::ClassTemplate: + case Decl::VarTemplate: case Decl::TypeAliasTemplate: case Decl::ObjCProtocol: case Decl::ObjCInterface: diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 122865b4686..6694192c880 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -239,6 +239,13 @@ namespace clang { ClassTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D); + RedeclarableResult + VisitVarTemplateSpecializationDeclImpl(VarTemplateSpecializationDecl *D); + void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) { + VisitVarTemplateSpecializationDeclImpl(D); + } + void VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *VD); void VisitEnumConstantDecl(EnumConstantDecl *ECD); @@ -252,13 +259,15 @@ namespace clang { void VisitFieldDecl(FieldDecl *FD); void VisitMSPropertyDecl(MSPropertyDecl *FD); void VisitIndirectFieldDecl(IndirectFieldDecl *FD); - void VisitVarDecl(VarDecl *VD); + RedeclarableResult VisitVarDeclImpl(VarDecl *D); + void VisitVarDecl(VarDecl *VD) { VisitVarDeclImpl(VD); } void VisitImplicitParamDecl(ImplicitParamDecl *PD); void VisitParmVarDecl(ParmVarDecl *PD); void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); void VisitTemplateDecl(TemplateDecl *D); RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); + void VisitVarTemplateDecl(VarTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); @@ -917,7 +926,7 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { FD->Chaining[I] = ReadDeclAs<NamedDecl>(Record, Idx); } -void ASTDeclReader::VisitVarDecl(VarDecl *VD) { +ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { RedeclarableResult Redecl = VisitRedeclarable(VD); VisitDeclaratorDecl(VD); @@ -950,6 +959,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) { SourceLocation POI = ReadSourceLocation(Record, Idx); Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI); } + + return Redecl; } void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { @@ -1418,6 +1429,40 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { } } +void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { + RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D); + + if (ThisDeclID == Redecl.getFirstID()) { + // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of + // the specializations. + SmallVector<serialization::DeclID, 2> SpecIDs; + SpecIDs.push_back(0); + + // Specializations. + unsigned Size = Record[Idx++]; + SpecIDs[0] += Size; + for (unsigned I = 0; I != Size; ++I) + SpecIDs.push_back(ReadDeclID(Record, Idx)); + + // Partial specializations. + Size = Record[Idx++]; + SpecIDs[0] += Size; + for (unsigned I = 0; I != Size; ++I) + SpecIDs.push_back(ReadDeclID(Record, Idx)); + + VarTemplateDecl::Common *CommonPtr = D->getCommonPtr(); + if (SpecIDs[0]) { + typedef serialization::DeclID DeclID; + + // FIXME: Append specializations! + CommonPtr->LazySpecializations = + new (Reader.getContext()) DeclID[SpecIDs.size()]; + memcpy(CommonPtr->LazySpecializations, SpecIDs.data(), + SpecIDs.size() * sizeof(DeclID)); + } + } +} + ASTDeclReader::RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( ClassTemplateSpecializationDecl *D) { @@ -1528,6 +1573,89 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { } } +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( + VarTemplateSpecializationDecl *D) { + RedeclarableResult Redecl = VisitVarDeclImpl(D); + + ASTContext &C = Reader.getContext(); + if (Decl *InstD = ReadDecl(Record, Idx)) { + if (VarTemplateDecl *VTD = dyn_cast<VarTemplateDecl>(InstD)) { + D->SpecializedTemplate = VTD; + } else { + SmallVector<TemplateArgument, 8> TemplArgs; + Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); + TemplateArgumentList *ArgList = TemplateArgumentList::CreateCopy( + C, TemplArgs.data(), TemplArgs.size()); + VarTemplateSpecializationDecl::SpecializedPartialSpecialization *PS = + new (C) + VarTemplateSpecializationDecl::SpecializedPartialSpecialization(); + PS->PartialSpecialization = + cast<VarTemplatePartialSpecializationDecl>(InstD); + PS->TemplateArgs = ArgList; + D->SpecializedTemplate = PS; + } + } + + // Explicit info. + if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) { + VarTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo = + new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo; + ExplicitInfo->TypeAsWritten = TyInfo; + ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx); + ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx); + D->ExplicitInfo = ExplicitInfo; + } + + SmallVector<TemplateArgument, 8> TemplArgs; + Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); + D->TemplateArgs = + TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size()); + D->PointOfInstantiation = ReadSourceLocation(Record, Idx); + D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++]; + + bool writtenAsCanonicalDecl = Record[Idx++]; + if (writtenAsCanonicalDecl) { + VarTemplateDecl *CanonPattern = ReadDeclAs<VarTemplateDecl>(Record, Idx); + if (D->isCanonicalDecl()) { // It's kept in the folding set. + if (VarTemplatePartialSpecializationDecl *Partial = + dyn_cast<VarTemplatePartialSpecializationDecl>(D)) { + Partial->SequenceNumber = + CanonPattern->getNextPartialSpecSequenceNumber(); + CanonPattern->getCommonPtr()->PartialSpecializations + .GetOrInsertNode(Partial); + } else { + CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D); + } + } + } + + return Redecl; +} + +void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D) { + RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); + + ASTContext &C = Reader.getContext(); + D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx); + + unsigned NumArgs = Record[Idx++]; + if (NumArgs) { + D->NumArgsAsWritten = NumArgs; + D->ArgsAsWritten = new (C) TemplateArgumentLoc[NumArgs]; + for (unsigned i = 0; i != NumArgs; ++i) + D->ArgsAsWritten[i] = Reader.ReadTemplateArgumentLoc(F, Record, Idx); + } + + // These are read/set from/to the first declaration. + if (ThisDeclID == Redecl.getFirstID()) { + D->InstantiatedFromMember.setPointer( + ReadDeclAs<VarTemplatePartialSpecializationDecl>(Record, Idx)); + D->InstantiatedFromMember.setInt(Record[Idx++]); + } +} + void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { VisitTypeDecl(D); @@ -2178,6 +2306,15 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID); break; + case DECL_VAR_TEMPLATE: + D = VarTemplateDecl::CreateDeserialized(Context, ID); + break; + case DECL_VAR_TEMPLATE_SPECIALIZATION: + D = VarTemplateSpecializationDecl::CreateDeserialized(Context, ID); + break; + case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION: + D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID); + break; case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION: D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID); break; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 08d7f96fadd..142e7b12671 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -946,6 +946,9 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_CLASS_TEMPLATE); RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION); RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION); + RECORD(DECL_VAR_TEMPLATE); + RECORD(DECL_VAR_TEMPLATE_SPECIALIZATION); + RECORD(DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION); RECORD(DECL_FUNCTION_TEMPLATE); RECORD(DECL_TEMPLATE_TYPE_PARM); RECORD(DECL_NON_TYPE_TEMPLATE_PARM); @@ -5235,6 +5238,19 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, Record.push_back(reinterpret_cast<uint64_t>(D)); } +void ASTWriter::AddedCXXTemplateSpecialization( + const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { + // The specializations set is kept in the canonical template. + assert(!WritingAST && "Already writing the AST!"); + TD = TD->getCanonicalDecl(); + if (!(!D->isFromASTFile() && TD->isFromASTFile())) + return; // Not a source specialization added to a template from PCH. + + UpdateRecord &Record = DeclUpdates[TD]; + Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); + Record.push_back(reinterpret_cast<uint64_t>(D)); +} + void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D) { // The specializations set is kept in the canonical template. diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 87398e99aec..a3e883f057e 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -68,6 +68,9 @@ namespace clang { ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); + void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); + void VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); @@ -90,6 +93,7 @@ namespace clang { void VisitTemplateDecl(TemplateDecl *D); void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); + void VisitVarTemplateDecl(VarTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); @@ -1184,6 +1188,87 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl( Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION; } +void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) { + VisitRedeclarableTemplateDecl(D); + + if (D->isFirstDeclaration()) { + typedef llvm::FoldingSetVector<VarTemplateSpecializationDecl> VTSDSetTy; + VTSDSetTy &VTSDSet = D->getSpecializations(); + Record.push_back(VTSDSet.size()); + for (VTSDSetTy::iterator I = VTSDSet.begin(), E = VTSDSet.end(); I != E; + ++I) { + assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); + Writer.AddDeclRef(&*I, Record); + } + + typedef llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> + VTPSDSetTy; + VTPSDSetTy &VTPSDSet = D->getPartialSpecializations(); + Record.push_back(VTPSDSet.size()); + for (VTPSDSetTy::iterator I = VTPSDSet.begin(), E = VTPSDSet.end(); I != E; + ++I) { + assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); + Writer.AddDeclRef(&*I, Record); + } + } + Code = serialization::DECL_VAR_TEMPLATE; +} + +void ASTDeclWriter::VisitVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *D) { + VisitVarDecl(D); + + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + InstFrom = D->getSpecializedTemplateOrPartial(); + if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) { + Writer.AddDeclRef(InstFromD, Record); + } else { + Writer.AddDeclRef(InstFrom.get<VarTemplatePartialSpecializationDecl *>(), + Record); + Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record); + } + + // Explicit info. + Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record); + if (D->getTypeAsWritten()) { + Writer.AddSourceLocation(D->getExternLoc(), Record); + Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record); + } + + Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record); + Writer.AddSourceLocation(D->getPointOfInstantiation(), Record); + Record.push_back(D->getSpecializationKind()); + Record.push_back(D->isCanonicalDecl()); + + if (D->isCanonicalDecl()) { + // When reading, we'll add it to the folding set of the following template. + Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record); + } + + Code = serialization::DECL_VAR_TEMPLATE_SPECIALIZATION; +} + +void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D) { + VisitVarTemplateSpecializationDecl(D); + + Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); + + Record.push_back(D->getNumTemplateArgsAsWritten()); + for (int i = 0, e = D->getNumTemplateArgsAsWritten(); i != e; ++i) + Writer.AddTemplateArgumentLoc(D->getTemplateArgsAsWritten()[i], Record); + + Record.push_back(D->getSequenceNumber()); + + // These are read/set from/to the first declaration. + if (D->getPreviousDecl() == 0) { + Writer.AddDeclRef(D->getInstantiatedFromMember(), Record); + Record.push_back(D->isMemberSpecialization()); + } + + Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION; +} + void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D) { VisitDecl(D); |