/// Determines whether the given friend class template matches /// anything in the effective context. static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, ClassTemplateDecl *Friend) { AccessResult OnFailure = AR_inaccessible; // Check whether the friend is the template of a class in the // context chain. for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { CXXRecordDecl *Record = *I; // Figure out whether the current class has a template: ClassTemplateDecl *CTD; // A specialization of the template... if (isa<ClassTemplateSpecializationDecl>(Record)) { CTD = cast<ClassTemplateSpecializationDecl>(Record) ->getSpecializedTemplate(); // ... or the template pattern itself. } else { CTD = Record->getDescribedClassTemplate(); if (!CTD) continue; } // It's a match. if (Friend == CTD->getCanonicalDecl()) return AR_accessible; // If the context isn't dependent, it can't be a dependent match. if (!EC.isDependent()) continue; // If the template names don't match, it can't be a dependent // match. This isn't true in C++0x because of template aliases. if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) continue; // If the class's context can't instantiate to the friend's // context, it can't be a dependent match. if (!MightInstantiateTo(S, CTD->getDeclContext(), Friend->getDeclContext())) continue; // Otherwise, it's a dependent match. OnFailure = AR_dependent; } return OnFailure; }
void BlinkGCPluginConsumer::CheckRecord(RecordInfo* info) { if (IsIgnored(info)) return; CXXRecordDecl* record = info->record(); // TODO: what should we do to check unions? if (record->isUnion()) return; // If this is the primary template declaration, check its specializations. if (record->isThisDeclarationADefinition() && record->getDescribedClassTemplate()) { ClassTemplateDecl* tmpl = record->getDescribedClassTemplate(); for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin(); it != tmpl->spec_end(); ++it) { CheckClass(cache_.Lookup(*it)); } return; } CheckClass(info); }
bool VisitVarDecl(VarDecl *D) { if (Consumer->isInIncludedFile(D)) return true; const Type *Ty = D->getType().getTypePtr(); if (!Ty) return true; CXXRecordDecl *CXXRD = Ty->getAsCXXRecordDecl(); if (!CXXRD) return true; CXXRecordDecl *CXXRDT = CXXRD->getTemplateInstantiationPattern(); if (!CXXRDT) return true; ClassTemplateDecl *CTD = CXXRDT->getDescribedClassTemplate(); while (CTD && !CTD->isThisDeclarationADefinition()) { CTD = CTD->getPreviousDecl(); } if (!CTD || CTD != Consumer->TheVectorDecl) return true; ++Consumer->ValidInstanceNum; if (Consumer->ValidInstanceNum == Consumer->TransformationCounter) Consumer->TheVarDecl = D; return true; }
bool ReduceClassTemplateParameterASTVisitor::VisitClassTemplateDecl( ClassTemplateDecl *D) { if (ConsumerInstance->isInIncludedFile(D)) return true; ClassTemplateDecl *CanonicalD = D->getCanonicalDecl(); if (ConsumerInstance->VisitedDecls.count(CanonicalD)) return true; ConsumerInstance->VisitedDecls.insert(CanonicalD); if (!ConsumerInstance->isValidClassTemplateDecl(D)) return true; TemplateParameterSet ParamsSet; TemplateParameterVisitor ParameterVisitor(ParamsSet); CXXRecordDecl *CXXRD = D->getTemplatedDecl(); CXXRecordDecl *Def = CXXRD->getDefinition(); if (Def) ParameterVisitor.TraverseDecl(Def); // ISSUE: we should also check the parameter usage for partial template // specializations. For example: // template<typename T1, typename T2> struct S{}; // template<typename T1, typename T2> struct<T1 *, T2 *> S{...}; // T1 or T2 could be used in "..." // Also, we could have another bad transformation, for example, // template<bool, typename T> struct S{}; // template<typename T> struct<true, T> S{}; // if we remove bool and true, we will have two definitions for S TemplateParameterList *TPList; if (Def) { // make sure we use the params as in ParameterVisitor const ClassTemplateDecl *CT = Def->getDescribedClassTemplate(); TransAssert(CT && "NULL DescribedClassTemplate!"); TPList = CT->getTemplateParameters(); } else { TPList = CanonicalD->getTemplateParameters(); } unsigned Index = 0; for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { const NamedDecl *ND = (*I); if (ParamsSet.count(ND)) { Index++; continue; } ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheClassTemplateDecl = CanonicalD; ConsumerInstance->TheParameterIndex = Index; ConsumerInstance->TheTemplateName = new TemplateName(CanonicalD); ConsumerInstance->setDefaultArgFlag(ND); } Index++; } return true; }
/// \brief Find the current instantiation that associated with the given type. static CXXRecordDecl * getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, QualType T) { if (T.isNull()) return 0; T = Context.getCanonicalType(T).getUnqualifiedType(); for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { // If we've hit a namespace or the global scope, then the // nested-name-specifier can't refer to the current instantiation. if (Ctx->isFileContext()) return 0; // Skip non-class contexts. CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); if (!Record) continue; // If this record type is not dependent, if (!Record->isDependentType()) return 0; // C++ [temp.dep.type]p1: // // In the definition of a class template, a nested class of a // class template, a member of a class template, or a member of a // nested class of a class template, a name refers to the current // instantiation if it is // -- the injected-class-name (9) of the class template or // nested class, // -- in the definition of a primary class template, the name // of the class template followed by the template argument // list of the primary template (as described below) // enclosed in <>, // -- in the definition of a nested class of a class template, // the name of the nested class referenced as a member of // the current instantiation, or // -- in the definition of a partial specialization, the name // of the class template followed by the template argument // list of the partial specialization enclosed in <>. If // the nth template parameter is a parameter pack, the nth // template argument is a pack expansion (14.6.3) whose // pattern is the name of the parameter pack. // (FIXME: parameter packs) // // All of these options come down to having the // nested-name-specifier type that is equivalent to the // injected-class-name of one of the types that is currently in // our context. if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) return Record; if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { QualType InjectedClassName = Template->getInjectedClassNameType(Context); if (T == Context.getCanonicalType(InjectedClassName)) return Template->getTemplatedDecl(); } // FIXME: check for class template partial specializations } return 0; }