//===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/ // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. //===----------------------------------------------------------------------===/ // // This file implements C++ template instantiation for declarations. // //===----------------------------------------------------------------------===/ #include "Sema.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "llvm/Support/Compiler.h" using namespace clang; namespace { class VISIBILITY_HIDDEN TemplateDeclInstantiator : public DeclVisitor { Sema &SemaRef; DeclContext *Owner; const TemplateArgumentList &TemplateArgs; public: typedef Sema::OwningExprResult OwningExprResult; TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, const TemplateArgumentList &TemplateArgs) : SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { } // FIXME: Once we get closer to completion, replace these manually-written // declarations with automatically-generated ones from // clang/AST/DeclNodes.def. Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); Decl *VisitTypedefDecl(TypedefDecl *D); Decl *VisitVarDecl(VarDecl *D); Decl *VisitFieldDecl(FieldDecl *D); Decl *VisitStaticAssertDecl(StaticAssertDecl *D); Decl *VisitEnumDecl(EnumDecl *D); Decl *VisitEnumConstantDecl(EnumConstantDecl *D); Decl *VisitCXXRecordDecl(CXXRecordDecl *D); Decl *VisitCXXMethodDecl(CXXMethodDecl *D); Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D); Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); Decl *VisitCXXConversionDecl(CXXConversionDecl *D); ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D); // Base case. FIXME: Remove once we can instantiate everything. Decl *VisitDecl(Decl *) { assert(false && "Template instantiation of unknown declaration kind!"); return 0; } // Helper functions for instantiating methods. QualType InstantiateFunctionType(FunctionDecl *D, llvm::SmallVectorImpl &Params); bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); }; } Decl * TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { assert(false && "Translation units cannot be instantiated"); return D; } Decl * TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { assert(false && "Namespaces cannot be instantiated"); return D; } Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; QualType T = D->getUnderlyingType(); if (T->isDependentType()) { T = SemaRef.InstantiateType(T, TemplateArgs, D->getLocation(), D->getDeclName()); if (T.isNull()) { Invalid = true; T = SemaRef.Context.IntTy; } } // Create the new typedef TypedefDecl *Typedef = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T); if (Invalid) Typedef->setInvalidDecl(); Owner->addDecl(SemaRef.Context, Typedef); return Typedef; } Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Instantiate the type of the declaration QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName()); if (T.isNull()) return 0; // Build the instantiated declaration VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T, D->getStorageClass(), D->getTypeSpecStartLoc()); Var->setThreadSpecified(D->isThreadSpecified()); Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); Var->setDeclaredInCondition(D->isDeclaredInCondition()); // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration); Owner->addDecl(SemaRef.Context, Var); if (D->getInit()) { OwningExprResult Init = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs); if (Init.isInvalid()) Var->setInvalidDecl(); else SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), D->hasCXXDirectInitializer()); } else { // FIXME: Call ActOnUninitializedDecl? (Not always) } return Var; } Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; QualType T = D->getType(); if (T->isDependentType()) { T = SemaRef.InstantiateType(T, TemplateArgs, D->getLocation(), D->getDeclName()); if (!T.isNull() && T->isFunctionType()) { // C++ [temp.arg.type]p3: // If a declaration acquires a function type through a type // dependent on a template-parameter and this causes a // declaration that does not use the syntactic form of a // function declarator to have function type, the program is // ill-formed. SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function) << T; T = QualType(); Invalid = true; } } Expr *BitWidth = D->getBitWidth(); if (Invalid) BitWidth = 0; else if (BitWidth) { OwningExprResult InstantiatedBitWidth = SemaRef.InstantiateExpr(BitWidth, TemplateArgs); if (InstantiatedBitWidth.isInvalid()) { Invalid = true; BitWidth = 0; } else BitWidth = InstantiatedBitWidth.takeAs(); } FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T, cast(Owner), D->getLocation(), D->isMutable(), BitWidth, D->getAccess(), 0); if (Field) { if (Invalid) Field->setInvalidDecl(); Owner->addDecl(SemaRef.Context, Field); } return Field; } Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { Expr *AssertExpr = D->getAssertExpr(); OwningExprResult InstantiatedAssertExpr = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs); if (InstantiatedAssertExpr.isInvalid()) return 0; OwningExprResult Message = SemaRef.Clone(D->getMessage()); Decl *StaticAssert = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(), move(InstantiatedAssertExpr), move(Message)).getAs(); return StaticAssert; } Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), /*PrevDecl=*/0); Enum->setInstantiationOfMemberEnum(D); Enum->setAccess(D->getAccess()); Owner->addDecl(SemaRef.Context, Enum); Enum->startDefinition(); llvm::SmallVector Enumerators; EnumConstantDecl *LastEnumConst = 0; for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(SemaRef.Context), ECEnd = D->enumerator_end(SemaRef.Context); EC != ECEnd; ++EC) { // The specified value for the enumerator. OwningExprResult Value = SemaRef.Owned((Expr *)0); if (Expr *UninstValue = EC->getInitExpr()) Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs); // Drop the initial value and continue. bool isInvalid = false; if (Value.isInvalid()) { Value = SemaRef.Owned((Expr *)0); isInvalid = true; } EnumConstantDecl *EnumConst = SemaRef.CheckEnumConstant(Enum, LastEnumConst, EC->getLocation(), EC->getIdentifier(), move(Value)); if (isInvalid) { if (EnumConst) EnumConst->setInvalidDecl(); Enum->setInvalidDecl(); } if (EnumConst) { Enum->addDecl(SemaRef.Context, EnumConst); Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst)); LastEnumConst = EnumConst; } } // FIXME: Fixup LBraceLoc and RBraceLoc SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(), Sema::DeclPtrTy::make(Enum), &Enumerators[0], Enumerators.size()); return Enum; } Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { assert(false && "EnumConstantDecls can only occur within EnumDecls."); return 0; } Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { CXXRecordDecl *PrevDecl = 0; if (D->isInjectedClassName()) PrevDecl = cast(Owner); CXXRecordDecl *Record = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, D->getLocation(), D->getIdentifier(), PrevDecl); Record->setImplicit(D->isImplicit()); Record->setAccess(D->getAccess()); if (!D->isInjectedClassName()) Record->setInstantiationOfMemberClass(D); Owner->addDecl(SemaRef.Context, Record); return Record; } Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { // Only handle actual methods; we'll deal with constructors, // destructors, etc. separately. if (D->getKind() != Decl::CXXMethod) return 0; Sema::LocalInstantiationScope Scope(SemaRef); llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) return 0; // Build the instantiated method declaration. CXXRecordDecl *Record = cast(Owner); CXXMethodDecl *Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), D->getDeclName(), T, D->isStatic(), D->isInline()); Method->setInstantiationOfMemberFunction(D); // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Method); Method->setParams(SemaRef.Context, Params.data(), Params.size()); if (InitMethodInstantiation(Method, D)) Method->setInvalidDecl(); NamedDecl *PrevDecl = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(), Sema::LookupOrdinaryName, true); // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) PrevDecl = 0; bool Redeclaration = false; bool OverloadableAttrRequired = false; SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration, /*FIXME:*/OverloadableAttrRequired); if (!Method->isInvalidDecl() || !PrevDecl) Owner->addDecl(SemaRef.Context, Method); return Method; } Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { Sema::LocalInstantiationScope Scope(SemaRef); llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) return 0; // Build the instantiated method declaration. CXXRecordDecl *Record = cast(Owner); QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); DeclarationName Name = SemaRef.Context.DeclarationNames.getCXXConstructorName( SemaRef.Context.getCanonicalType(ClassTy)); CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(), Name, T, D->isExplicit(), D->isInline(), false); Constructor->setInstantiationOfMemberFunction(D); // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Constructor); Constructor->setParams(SemaRef.Context, Params.data(), Params.size()); if (InitMethodInstantiation(Constructor, D)) Constructor->setInvalidDecl(); NamedDecl *PrevDecl = SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true); // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) PrevDecl = 0; bool Redeclaration = false; bool OverloadableAttrRequired = false; SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration, /*FIXME:*/OverloadableAttrRequired); Record->addedConstructor(SemaRef.Context, Constructor); Owner->addDecl(SemaRef.Context, Constructor); return Constructor; } Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { Sema::LocalInstantiationScope Scope(SemaRef); llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) return 0; assert(Params.size() == 0 && "Destructor with parameters?"); // Build the instantiated destructor declaration. CXXRecordDecl *Record = cast(Owner); QualType ClassTy = SemaRef.Context.getCanonicalType(SemaRef.Context.getTypeDeclType(Record)); CXXDestructorDecl *Destructor = CXXDestructorDecl::Create(SemaRef.Context, Record, D->getLocation(), SemaRef.Context.DeclarationNames.getCXXDestructorName(ClassTy), T, D->isInline(), false); Destructor->setInstantiationOfMemberFunction(D); if (InitMethodInstantiation(Destructor, D)) Destructor->setInvalidDecl(); bool Redeclaration = false; bool OverloadableAttrRequired = false; NamedDecl *PrevDecl = 0; SemaRef.CheckFunctionDeclaration(Destructor, PrevDecl, Redeclaration, /*FIXME:*/OverloadableAttrRequired); Owner->addDecl(SemaRef.Context, Destructor); return Destructor; } Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { Sema::LocalInstantiationScope Scope(SemaRef); llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) return 0; assert(Params.size() == 0 && "Destructor with parameters?"); // Build the instantiated conversion declaration. CXXRecordDecl *Record = cast(Owner); QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); QualType ConvTy = SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType()); CXXConversionDecl *Conversion = CXXConversionDecl::Create(SemaRef.Context, Record, D->getLocation(), SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy), T, D->isInline(), D->isExplicit()); Conversion->setInstantiationOfMemberFunction(D); if (InitMethodInstantiation(Conversion, D)) Conversion->setInvalidDecl(); bool Redeclaration = false; bool OverloadableAttrRequired = false; NamedDecl *PrevDecl = 0; SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration, /*FIXME:*/OverloadableAttrRequired); Owner->addDecl(SemaRef.Context, Conversion); return Conversion; } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs, D->getLocation(), D->getDeclName()); if (OrigT.isNull()) return 0; QualType T = SemaRef.adjustParameterType(OrigT); if (D->getDefaultArg()) { // FIXME: Leave a marker for "uninstantiated" default // arguments. They only get instantiated on demand at the call // site. unsigned DiagID = SemaRef.Diags.getCustomDiagID(Diagnostic::Warning, "sorry, dropping default argument during template instantiation"); SemaRef.Diag(D->getDefaultArg()->getSourceRange().getBegin(), DiagID) << D->getDefaultArg()->getSourceRange(); } // Allocate the parameter ParmVarDecl *Param = 0; if (T == OrigT) Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T, D->getStorageClass(), 0); else Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T, OrigT, D->getStorageClass(), 0); // Note: we don't try to instantiate function parameters until after // we've instantiated the function's type. Therefore, we don't have // to check for 'void' parameter types here. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); return Param; } Decl * TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { // Since parameter types can decay either before or after // instantiation, we simply treat OriginalParmVarDecls as // ParmVarDecls the same way, and create one or the other depending // on what happens after template instantiation. return VisitParmVarDecl(D); } Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner, const TemplateArgumentList &TemplateArgs) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); return Instantiator.Visit(D); } /// \brief Instantiates the type of the given function, including /// instantiating all of the function parameters. /// /// \param D The function that we will be instantiated /// /// \param Params the instantiated parameter declarations /// \returns the instantiated function's type if successfull, a NULL /// type if there was an error. QualType TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D, llvm::SmallVectorImpl &Params) { bool InvalidDecl = false; // Instantiate the function parameters TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs); llvm::SmallVector ParamTys; for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) { if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) { if (PInst->getType()->isVoidType()) { SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type); PInst->setInvalidDecl(); } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(), PInst->getType(), diag::err_abstract_type_in_decl, Sema::AbstractParamType)) PInst->setInvalidDecl(); Params.push_back(PInst); ParamTys.push_back(PInst->getType()); if (PInst->isInvalidDecl()) InvalidDecl = true; } else InvalidDecl = true; } // FIXME: Deallocate dead declarations. if (InvalidDecl) return QualType(); const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType(); assert(Proto && "Missing prototype?"); QualType ResultType = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs, D->getLocation(), D->getDeclName()); if (ResultType.isNull()) return QualType(); return SemaRef.BuildFunctionType(ResultType, ParamTys.data(), ParamTys.size(), Proto->isVariadic(), Proto->getTypeQuals(), D->getLocation(), D->getDeclName()); } /// \brief Initializes common fields of an instantiated method /// declaration (New) from the corresponding fields of its template /// (Tmpl). /// /// \returns true if there was an error bool TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl) { CXXRecordDecl *Record = cast(Owner); New->setAccess(Tmpl->getAccess()); if (Tmpl->isVirtualAsWritten()) { New->setVirtualAsWritten(true); Record->setAggregate(false); Record->setPOD(false); Record->setPolymorphic(true); } if (Tmpl->isDeleted()) New->setDeleted(); if (Tmpl->isPure()) { New->setPure(); Record->setAbstract(true); } // FIXME: attributes // FIXME: New needs a pointer to Tmpl return false; } /// \brief Instantiate the definition of the given function from its /// template. /// /// \param Function the already-instantiated declaration of a /// function. void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function) { // FIXME: make this work for function template specializations, too. if (Function->isInvalidDecl()) return; // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getInstantiatedFromMemberFunction(); Stmt *Pattern = 0; if (PatternDecl) Pattern = PatternDecl->getBody(Context, PatternDecl); if (!Pattern) return; InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst) return; ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); // Introduce a new scope where local variable instantiations will be // recorded. LocalInstantiationScope Scope(*this); // Introduce the instantiated function parameters into the local // instantiation scope. for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) Scope.InstantiatedLocal(PatternDecl->getParamDecl(I), Function->getParamDecl(I)); // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. DeclContext *PreviousContext = CurContext; CurContext = Function; // Instantiate the function body. OwningStmtResult Body = InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function)); ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), /*IsInstantiation=*/true); CurContext = PreviousContext; DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); } /// \brief Instantiate the definition of the given variable from its /// template. /// /// \param Var the already-instantiated declaration of a variable. void Sema::InstantiateVariableDefinition(VarDecl *Var) { // FIXME: Implement this! } static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (D->getKind() != Other->getKind()) return false; if (CXXRecordDecl *Record = dyn_cast(Other)) return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass()) == Ctx.getCanonicalDecl(D); if (FunctionDecl *Function = dyn_cast(Other)) return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction()) == Ctx.getCanonicalDecl(D); if (EnumDecl *Enum = dyn_cast(Other)) return Ctx.getCanonicalDecl(Enum->getInstantiatedFromMemberEnum()) == Ctx.getCanonicalDecl(D); // FIXME: How can we find instantiations of anonymous unions? return D->getDeclName() && isa(Other) && D->getDeclName() == cast(Other)->getDeclName(); } template static NamedDecl *findInstantiationOf(ASTContext &Ctx, NamedDecl *D, ForwardIterator first, ForwardIterator last) { for (; first != last; ++first) if (isInstantiationOf(Ctx, D, *first)) return cast(*first); return 0; } /// \brief Find the instantiation of the given declaration within the /// current instantiation. /// /// This routine is intended to be used when \p D is a declaration /// referenced from within a template, that needs to mapped into the /// corresponding declaration within an instantiation. For example, /// given: /// /// \code /// template /// struct X { /// enum Kind { /// KnownValue = sizeof(T) /// }; /// /// bool getKind() const { return KnownValue; } /// }; /// /// template struct X; /// \endcode /// /// In the instantiation of X::getKind(), we need to map the /// EnumConstantDecl for KnownValue (which refers to /// X::::KnownValue) to its instantiation /// (X::::KnownValue). InstantiateCurrentDeclRef() performs /// this mapping from within the instantiation of X. NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) { DeclContext *ParentDC = D->getDeclContext(); if (isa(D) || ParentDC->isFunctionOrMethod()) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. return cast(CurrentInstantiationScope->getInstantiationOf(D)); } if (NamedDecl *ParentDecl = dyn_cast(ParentDC)) { ParentDecl = InstantiateCurrentDeclRef(ParentDecl); if (!ParentDecl) return 0; ParentDC = cast(ParentDecl); } if (ParentDC != D->getDeclContext()) { // We performed some kind of instantiation in the parent context, // so now we need to look into the instantiated parent context to // find the instantiation of the declaration D. NamedDecl *Result = 0; if (D->getDeclName()) { DeclContext::lookup_result Found = ParentDC->lookup(Context, D->getDeclName()); Result = findInstantiationOf(Context, D, Found.first, Found.second); } else { // Since we don't have a name for the entity we're looking for, // our only option is to walk through all of the declarations to // find that name. This will occur in a few cases: // // - anonymous struct/union within a template // - unnamed class/struct/union/enum within a template // // FIXME: Find a better way to find these instantiations! Result = findInstantiationOf(Context, D, ParentDC->decls_begin(Context), ParentDC->decls_end(Context)); } assert(Result && "Unable to find instantiation of declaration!"); D = Result; } if (CXXRecordDecl *Record = dyn_cast(D)) if (ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate()) { // When the declaration D was parsed, it referred to the current // instantiation. Therefore, look through the current context, // which contains actual instantiations, to find the // instantiation of the "current instantiation" that D refers // to. Alternatively, we could just instantiate the // injected-class-name with the current template arguments, but // such an instantiation is far more expensive. for (DeclContext *DC = CurContext; !DC->isFileContext(); DC = DC->getParent()) { if (ClassTemplateSpecializationDecl *Spec = dyn_cast(DC)) if (Context.getCanonicalDecl(Spec->getSpecializedTemplate()) == Context.getCanonicalDecl(ClassTemplate)) return Spec; } assert(false && "Unable to find declaration for the current instantiation"); } return D; }