diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 3c140824d066c..65d41c79d6a2d 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -1404,8 +1404,12 @@ void TClass::Init(const char *name, Version_t cversion, } } - fClassInfo = gInterpreter->ClassInfo_Factory(givenInfo); - fCanLoadClassInfo = false; // avoids calls to LoadClassInfo() if info is already loaded + if (!invalid) { + fClassInfo = gInterpreter->ClassInfo_Factory(givenInfo); + fCanLoadClassInfo = false; // avoids calls to LoadClassInfo() if info is already loaded + if (fState <= kEmulated) + fState = kInterpreted; + } } // We need to check if the class it is not fwd declared for the cases where we @@ -6053,6 +6057,8 @@ void TClass::SetUnloaded() GetName(),(int)fState); } + InsertTClassInRegistryRAII insertRAII(fState, fName, fNoInfoOrEmuOrFwdDeclNameRegistry); + // Make sure SetClassInfo, re-calculated the state. fState = kForwardDeclared; diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx index f68e9ee930f20..fdcce7790be32 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -6466,36 +6466,88 @@ Bool_t TCling::IsAutoLoadNamespaceCandidate(const clang::NamespaceDecl* nsDecl) } //////////////////////////////////////////////////////////////////////////////// -/// Internal function. Inform a TClass about its new TagDecl or NamespaceDecl. +/// Internal function. Actually do the update of the ClassInfo when seeing +// new TagDecl or NamespaceDecl. +void TCling::RefreshClassInfo(TClass *cl, const clang::NamedDecl *def, bool alias) +{ -void TCling::UpdateClassInfoWithDecl(const void* vTD) + TClingClassInfo *cci = ((TClingClassInfo *)cl->fClassInfo); + if (cci) { + // If we only had a forward declaration then update the + // TClingClassInfo with the definition if we have it now. + const NamedDecl *oldDef = llvm::dyn_cast_or_null(cci->GetDecl()); + if (!oldDef || (def && def != oldDef)) { + cl->ResetCaches(); + TClass::RemoveClassDeclId(cci->GetDeclId()); + if (def) { + // It's a tag decl, not a namespace decl. + cci->Init(*cci->GetType()); + TClass::AddClassToDeclIdMap(cci->GetDeclId(), cl); + } + } + } else if (!cl->TestBit(TClass::kLoading) && !cl->fHasRootPcmInfo) { + cl->ResetCaches(); + // yes, this is almost a waste of time, but we do need to lookup + // the 'type' corresponding to the TClass anyway in order to + // preserve the opaque typedefs (Double32_t) + if (!alias && def != nullptr) + cl->fClassInfo = (ClassInfo_t *)new TClingClassInfo(fInterpreter, def); + else + cl->fClassInfo = (ClassInfo_t *)new TClingClassInfo(fInterpreter, cl->GetName()); + if (((TClingClassInfo *)cl->fClassInfo)->IsValid()) { + // We now need to update the state and bits. + if (cl->fState != TClass::kHasTClassInit) { + // if (!cl->fClassInfo->IsValid()) cl->fState = TClass::kForwardDeclared; else + cl->fState = TClass::kInterpreted; + cl->ResetBit(TClass::kIsEmulation); + } + TClass::AddClassToDeclIdMap(((TClingClassInfo *)(cl->fClassInfo))->GetDeclId(), cl); + } else { + delete ((TClingClassInfo *)cl->fClassInfo); + cl->fClassInfo = nullptr; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Internal function. Inform a TClass about its new TagDecl or NamespaceDecl. +void TCling::UpdateClassInfoWithDecl(const NamedDecl* ND) { - const NamedDecl* ND = static_cast(vTD); - const TagDecl* td = dyn_cast(ND); + const TagDecl *td = dyn_cast(ND); + const NamespaceDecl *ns = dyn_cast(ND); + const NamedDecl *canon = nullptr; + std::string name; TagDecl* tdDef = 0; if (td) { - tdDef = td->getDefinition(); + canon = tdDef = td->getDefinition(); // Let's pass the decl to the TClass only if it has a definition. if (!tdDef) return; - td = tdDef; - ND = td; - if (llvm::isa(td->getDeclContext())) { + if (!tdDef->isCompleteDefinition() || llvm::isa(tdDef->getDeclContext())) { + // Ignore incomplete definition. // Ignore declaration within a function. return; } - clang::QualType type( td->getTypeForDecl(), 0 ); - auto declName=ND->getNameAsString(); + auto declName = tdDef->getNameAsString(); + // Check if we have registered the unqualified name into the list + // of TClass that are in kNoInfo, kEmulated or kFwdDeclaredState. + // Since this is used as heureutistic to avoid spurrious calls to GetNormalizedName + // the unqualified name is sufficient (and the fully qualified name might be + // 'wrong' if there is difference in spelling in the template paramters (for example) if (!TClass::HasNoInfoOrEmuOrFwdDeclaredDecl(declName.c_str())){ -// printf ("Impossible to find a TClassEntry in kNoInfo or kEmulated the decl of which would be called %s. Skip w/o building the normalized name.\n",declName ); + // fprintf (stderr,"WARNING: Impossible to find a TClassEntry in kNoInfo or kEmulated the decl of which would be called %s. Skip w/o building the normalized name.\n",declName.c_str() ); return; } + clang::QualType type(tdDef->getTypeForDecl(), 0); ROOT::TMetaUtils::GetNormalizedName(name, type, *fInterpreter, *fNormalizedCtxt); + } else if (ns) { + canon = ns->getCanonicalDecl(); + name = ND->getQualifiedNameAsString(); } else { - name = ND->getNameAsString(); + name = ND->getQualifiedNameAsString(); } // Supposedly we are being called while something is being @@ -6506,35 +6558,12 @@ void TCling::UpdateClassInfoWithDecl(const void* vTD) // for example vector and vector TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name.c_str()); if (cl && GetModTClasses().find(cl) == GetModTClasses().end()) { - TClingClassInfo* cci = ((TClingClassInfo*)cl->fClassInfo); - if (cci) { - // If we only had a forward declaration then update the - // TClingClassInfo with the definition if we have it now. - const TagDecl* tdOld = llvm::dyn_cast_or_null(cci->GetDecl()); - if (!tdOld || (tdDef && tdDef != tdOld)) { - cl->ResetCaches(); - TClass::RemoveClassDeclId(cci->GetDeclId()); - if (td) { - // It's a tag decl, not a namespace decl. - cci->Init(*cci->GetType()); - TClass::AddClassToDeclIdMap(cci->GetDeclId(), cl); - } - } - } else if (!cl->TestBit(TClass::kLoading) && !cl->fHasRootPcmInfo) { - cl->ResetCaches(); - // yes, this is almost a waste of time, but we do need to lookup - // the 'type' corresponding to the TClass anyway in order to - // preserve the opaque typedefs (Double32_t) - cl->fClassInfo = (ClassInfo_t *)new TClingClassInfo(fInterpreter, cl->GetName()); - // We now need to update the state and bits. - if (cl->fState != TClass::kHasTClassInit) { - // if (!cl->fClassInfo->IsValid()) cl->fState = TClass::kForwardDeclared; else - cl->fState = TClass::kInterpreted; - cl->ResetBit(TClass::kIsEmulation); - } - TClass::AddClassToDeclIdMap(((TClingClassInfo*)(cl->fClassInfo))->GetDeclId(), cl); - } + RefreshClassInfo(cl, canon, false); } + // And here we should find the other 'aliases' (eg. vector) + // and update them too: + // foreach(aliascl in gROOT->GetListOfClasses()->FindAliasesOf(name.c_str())) + // RefreshClassInfo(cl, tdDef, true); } //////////////////////////////////////////////////////////////////////////////// diff --git a/core/metacling/src/TCling.h b/core/metacling/src/TCling.h index 2871c32d4cd7b..b1bd2daf2bd29 100644 --- a/core/metacling/src/TCling.h +++ b/core/metacling/src/TCling.h @@ -47,7 +47,9 @@ namespace clang { class DeclContext; class EnumDecl; class FunctionDecl; + class NamedDecl; class NamespaceDecl; + class TagDecl; class Type; class QualType; } @@ -313,7 +315,8 @@ class TCling final : public TInterpreter { static void UpdateClassInfo(char* name, Long_t tagnum); static void UpdateClassInfoWork(const char* name); - void UpdateClassInfoWithDecl(const void* vTD); + void RefreshClassInfo(TClass *cl, const clang::NamedDecl *def, bool alias); + void UpdateClassInfoWithDecl(const clang::NamedDecl* ND); static void UpdateAllCanvases(); // Misc diff --git a/interpreter/cling/include/cling/Utils/ParserStateRAII.h b/interpreter/cling/include/cling/Utils/ParserStateRAII.h index 8ecb1a5a28b5a..ed33160a082b2 100644 --- a/interpreter/cling/include/cling/Utils/ParserStateRAII.h +++ b/interpreter/cling/include/cling/Utils/ParserStateRAII.h @@ -47,6 +47,7 @@ namespace cling { ParserStateRAII(clang::Parser& p, bool skipToEOF); ~ParserStateRAII(); + void SetSkipToEOF(bool newvalue) { SkipToEOF = newvalue; } }; } // end namespace cling diff --git a/interpreter/cling/lib/Interpreter/LookupHelper.cpp b/interpreter/cling/lib/Interpreter/LookupHelper.cpp index 794d6532052d7..af1ca3f764230 100644 --- a/interpreter/cling/lib/Interpreter/LookupHelper.cpp +++ b/interpreter/cling/lib/Interpreter/LookupHelper.cpp @@ -38,6 +38,13 @@ namespace cling { class StartParsingRAII { LookupHelper& m_LH; llvm::SaveAndRestore SaveIsRecursivelyRunning; + // Save and restore the state of the Parser and lexer. + // Note: ROOT::Internal::ParsingStateRAII also save and restore the state of + // Sema, including pending instantiation for example. It is not clear + // whether we need to do so here too or whether we need to also see the + // "on-going" semantic information ... For now, we leave Sema untouched. + clang::Preprocessor::CleanupAndRestoreCacheRAII fCleanupRAII; + clang::Parser::ParserCurTokRestoreRAII fSavedCurToken; ParserStateRAII ResetParserState; void prepareForParsing(llvm::StringRef code, llvm::StringRef bufferName, LookupHelper::DiagSetting diagOnOff); @@ -46,6 +53,8 @@ namespace cling { llvm::StringRef bufferName, LookupHelper::DiagSetting diagOnOff) : m_LH(LH), SaveIsRecursivelyRunning(LH.IsRecursivelyRunning), + fCleanupRAII(LH.m_Parser.get()->getPreprocessor()), + fSavedCurToken(*LH.m_Parser.get()), ResetParserState(*LH.m_Parser.get(), !LH.IsRecursivelyRunning /*skipToEOF*/) { LH.IsRecursivelyRunning = true; @@ -1237,7 +1246,8 @@ namespace cling { llvm::StringRef funcName, Interpreter* Interp, UnqualifiedId &FuncId, - LookupHelper::DiagSetting diagOnOff) { + LookupHelper::DiagSetting diagOnOff, + ParserStateRAII &ResetParserState) { // Use a very simple parse step that dectect whether the name search (which // is already supposed to be an unqualified name) is a simple identifier, @@ -1336,6 +1346,7 @@ namespace cling { // Create a fake file to parse the function name. // // FIXME:, TODO: Cleanup that complete mess. + ResetParserState.SetSkipToEOF(true); { PP.getDiagnostics().setSuppressAllDiagnostics(diagOnOff == LookupHelper::NoDiagnostics); @@ -1410,9 +1421,9 @@ namespace cling { S.EnterDeclaratorContext(P.getCurScope(), foundDC); UnqualifiedId FuncId; - ParserStateRAII ResetParserState(P, true /*skipToEOF*/); - if (!ParseWithShortcuts(foundDC, Context, funcName, Interp, - FuncId, diagOnOff)) { + ParserStateRAII ResetParserState(P, false /*skipToEOF*/); + if (!ParseWithShortcuts(foundDC, Context, funcName, Interp, FuncId, + diagOnOff, ResetParserState)) { // Failed parse, cleanup. // Destroy the scope we created first, and // restore the original.