void DeclCollector::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { assert(D->isImplicit()); // We need to mark the decls coming from the modules if (comesFromASTReader(RD) || comesFromASTReader(D)) { Decl* implicitD = const_cast<Decl*>(D); implicitD->addAttr(UsedAttr::CreateImplicit(implicitD->getASTContext())); } }
bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) { // if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed // pipe it directly to codegen. if (comesFromASTReader(DGR)) { if (m_CodeGen) { for (DeclGroupRef::iterator I = DGR.begin(), E = DGR.end(); I != E; ++I) { if (NamespaceDecl* ND = dyn_cast<NamespaceDecl>(*I)) { for (NamespaceDecl::decl_iterator IN = ND->decls_begin(), EN = ND->decls_end(); IN != EN; ++IN) // Recurse over decls inside the namespace, like // CodeGenModule::EmitNamespace() does. HandleTopLevelDecl(DeclGroupRef(*IN)); } else { if (!shouldIgnoreDeclFromASTReader(*I)) { m_CodeGen->HandleTopLevelDecl(DeclGroupRef(*I)); } // FIXME: once modules are there this is not needed anymore. // it is used to simulate modules and the ASTDeserializationListener // for sources that are included to describe the library that was // built from the sources (ACLiC). if (!(*I)->isFromASTFile() && m_Interp->getASTDeserializationListener()) m_Interp->getASTDeserializationListener()->DeclRead(0, *I); } } } return true; } Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleTopLevelDecl); m_CurTransaction->append(DCI); return true; }
void DeclCollector::HandleInterestingDecl(DeclGroupRef DGR) { assert(m_CurTransaction && "Missing transction"); Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleInterestingDecl); m_CurTransaction->append(DCI); if (m_Consumer && (!comesFromASTReader(DGR) || !shouldIgnore(*DGR.begin()))) m_Consumer->HandleTopLevelDecl(DGR); }
void DeclCollector::HandleCXXStaticMemberVarInstantiation(VarDecl *D) { assert(m_CurTransaction && "Missing transction"); Transaction::DelayCallInfo DCI(DeclGroupRef(D), Transaction::kCCIHandleCXXStaticMemberVarInstantiation); m_CurTransaction->append(DCI); if (m_Consumer && (!comesFromASTReader(DeclGroupRef(D)) || !shouldIgnore(D))) m_Consumer->HandleCXXStaticMemberVarInstantiation(D); }
void DeclCollector::HandleTagDeclDefinition(TagDecl* TD) { assert(m_CurTransaction && "Missing transction"); Transaction::DelayCallInfo DCI(DeclGroupRef(TD), Transaction::kCCIHandleTagDeclDefinition); m_CurTransaction->append(DCI); if (m_Consumer && (!comesFromASTReader(DeclGroupRef(TD)) || !shouldIgnore(TD))) m_Consumer->HandleTagDeclDefinition(TD); }
void DeclCollector::HandleInterestingDecl(DeclGroupRef DGR) { // if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed // pipe it directly to codegen. if (comesFromASTReader(DGR)) { HandleTopLevelDecl(DGR); return; } Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleInterestingDecl); m_CurTransaction->append(DCI); }
void DeclCollector::CompleteTentativeDefinition(VarDecl* VD) { assert(m_CurTransaction && "Missing transction"); // C has tentative definitions which we might need to deal with when running // in C mode. Transaction::DelayCallInfo DCI(DeclGroupRef(VD), Transaction::kCCICompleteTentativeDefinition); m_CurTransaction->append(DCI); if (m_Consumer && (!comesFromASTReader(DeclGroupRef(VD)) || !shouldIgnore(VD))) m_Consumer->CompleteTentativeDefinition(VD); }
void DeclCollector::HandleTagDeclDefinition(TagDecl* TD) { // if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed // pipe it directly to codegen. if (comesFromASTReader(DeclGroupRef(TD))) { if (m_CodeGen) m_CodeGen->HandleTagDeclDefinition(TD); return; } Transaction::DelayCallInfo DCI(DeclGroupRef(TD), Transaction::kCCIHandleTagDeclDefinition); m_CurTransaction->append(DCI); }
void DeclCollector::HandleCXXStaticMemberVarInstantiation(VarDecl *D) { // if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed // pipe it directly to codegen. if (comesFromASTReader(DeclGroupRef(D))) { if (m_CodeGen && !shouldIgnoreDeclFromASTReader(D)) m_CodeGen->HandleCXXStaticMemberVarInstantiation(D); return; } Transaction::DelayCallInfo DCI(DeclGroupRef(D), Transaction::kCCIHandleCXXStaticMemberVarInstantiation); m_CurTransaction->append(DCI); }
void DeclCollector::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) { // if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed // pipe it directly to codegen. if (comesFromASTReader(DeclGroupRef(D))) { if (m_CodeGen) m_CodeGen->HandleCXXImplicitFunctionInstantiation(D); return; } Transaction::DelayCallInfo DCI(DeclGroupRef(D), Transaction::kCCIHandleCXXImplicitFunctionInstantiation); m_CurTransaction->append(DCI); }
void Transaction::forceAppend(DelayCallInfo DCI) { assert(!DCI.m_DGR.isNull() && "Appending null DGR?!"); assert((getState() == kCollecting || getState() == kCompleted) && "Must not be"); bool checkForWrapper = !m_WrapperFD; #ifndef NDEBUG // Check for duplicates for (size_t i = 0, e = m_DeclQueue.size(); i < e; ++i) { DelayCallInfo &oldDCI (m_DeclQueue[i]); // FIXME: This is possible bug in clang, which will instantiate one and // the same CXXStaticMemberVar several times. This happens when there are // two dependent expressions and the first uses another declaration from // the redeclaration chain. This will force Sema in to instantiate the // definition (usually the most recent decl in the chain) and then the // second expression might referece the definition (which was already) // instantiated, but Sema seems not to keep track of these kinds of // instantiations, even though the points of instantiation are the same! // // This should be investigated further when we merge with newest clang. // This is triggered by running the roottest: ./root/io/newstl if (oldDCI.m_Call == kCCIHandleCXXStaticMemberVarInstantiation) continue; // It is possible to have duplicate calls to HandleVTable with the same // declaration, because each time Sema believes a vtable is used it emits // that callback. // For reference (clang::CodeGen::CodeGenModule::EmitVTable). if (oldDCI.m_Call != kCCIHandleVTable) assert(oldDCI != DCI && "Duplicates?!"); } // We want to assert there is only one wrapper per transaction. checkForWrapper = true; #endif // register the wrapper if any. if (checkForWrapper && !DCI.m_DGR.isNull() && DCI.m_DGR.isSingleDecl()) { if (FunctionDecl* FD = dyn_cast<FunctionDecl>(DCI.m_DGR.getSingleDecl())){ if (checkForWrapper && utils::Analyze::IsWrapper(FD)) { assert(!m_WrapperFD && "Two wrappers in one transaction?"); m_WrapperFD = FD; } } } if (comesFromASTReader(DCI.m_DGR)) m_DeserializedDeclQueue.push_back(DCI); else m_DeclQueue.push_back(DCI); }
void DeclCollector::HandleVTable(CXXRecordDecl* RD) { assert(m_CurTransaction && "Missing transction"); Transaction::DelayCallInfo DCI(DeclGroupRef(RD), Transaction::kCCIHandleVTable); m_CurTransaction->append(DCI); if (m_Consumer && (!comesFromASTReader(DeclGroupRef(RD)) || !shouldIgnore(RD))) m_Consumer->HandleVTable(RD); // Intentional no-op. It comes through Sema::DefineUsedVTables, which // comes either Sema::ActOnEndOfTranslationUnit or while instantiating a // template. In our case we will do it on transaction commit, without // keeping track of used vtables, because we have cases where we bypass the // clang/AST and directly ask the module so that we have to generate // everything without extra smartness. }
bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) { if (!Transform(DGR)) return false; if (DGR.isNull()) return true; assert(m_CurTransaction && "Missing transction"); Transaction::DelayCallInfo DCI(DGR, Transaction::kCCIHandleTopLevelDecl); m_CurTransaction->append(DCI); if (!m_Consumer || getTransaction()->getIssuedDiags() == Transaction::kErrors) return true; if (comesFromASTReader(DGR)) { for (DeclGroupRef::iterator DI = DGR.begin(), DE = DGR.end(); DI != DE; ++DI) { DeclGroupRef SplitDGR(*DI); // FIXME: The special namespace treatment (not sending itself to // CodeGen, but only its content - if the contained decl should be // emitted) works around issue with the static initialization when // having a PCH and loading a library. We don't want to generate // code for the static that will come through the library. // // This will be fixed with the clang::Modules. Make sure we remember. // assert(!getCI()->getLangOpts().Modules && "Please revisit!"); if (NamespaceDecl* ND = dyn_cast<NamespaceDecl>(*DI)) { for (NamespaceDecl::decl_iterator NDI = ND->decls_begin(), EN = ND->decls_end(); NDI != EN; ++NDI) { // Recurse over decls inside the namespace, like // CodeGenModule::EmitNamespace() does. if (!shouldIgnore(*NDI)) m_Consumer->HandleTopLevelDecl(DeclGroupRef(*NDI)); } } else if (!shouldIgnore(*DI)) { m_Consumer->HandleTopLevelDecl(DeclGroupRef(*DI)); } continue; } } else { m_Consumer->HandleTopLevelDecl(DGR); } return true; }
void DeclCollector::HandleVTable(CXXRecordDecl* RD, bool DefinitionRequired) { // if that decl comes from an AST File, i.e. PCH/PCM, no transaction needed // pipe it directly to codegen. if (comesFromASTReader(DeclGroupRef(RD))) { // FIXME: when is the vtable part of the library? if (m_CodeGen) m_CodeGen->HandleVTable(RD, DefinitionRequired); return; } Transaction::DelayCallInfo DCI(DeclGroupRef(RD), Transaction::kCCIHandleVTable); m_CurTransaction->append(DCI); // Intentional no-op. It comes through Sema::DefineUsedVTables, which // comes either Sema::ActOnEndOfTranslationUnit or while instantiating a // template. In our case we will do it on transaction commit, without // keeping track of used vtables, because we have cases where we bypass the // clang/AST and directly ask the module so that we have to generate // everything without extra smartness. }
bool DeclCollector::comesFromASTReader(const Decl* D) const { // The operation is const but clang::DeclGroupRef doesn't allow us to // express it. return comesFromASTReader(DeclGroupRef(const_cast<Decl*>(D))); }