From 35b42b99a05cdcea3f5f18aa7711440c7cd44547 Mon Sep 17 00:00:00 2001 From: Danilo Piparo Date: Tue, 18 Aug 2026 21:01:46 +0200 Subject: [PATCH 1/4] [meta] Ctor name lookup is not enough for the class info the mechanism in place to allow the initialisation of TClingClassInfo based on names of forward declared classes was a bit too loose. It also allowed for finding a class by the name of its constructor. Fixes ROOT-10311 --- core/metacling/src/TClingClassInfo.cxx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/metacling/src/TClingClassInfo.cxx b/core/metacling/src/TClingClassInfo.cxx index 434996e2cb5aa..6a703d627cb1a 100644 --- a/core/metacling/src/TClingClassInfo.cxx +++ b/core/metacling/src/TClingClassInfo.cxx @@ -99,9 +99,14 @@ TClingClassInfo::TClingClassInfo(cling::Interpreter *interp, const char *name, b &type, intantiateTemplate); } } + // The lookup finds the decl if the name corresponds to a namespace or a fully defined + // class; just a type in presence of a forward declaration of a class. + // This code identifies that case and prevents that a class type is found if the name + // of a constructor is passed (see ROOT-10311). if (!decl && type) { - if (const auto *TD = type->getAsTagDecl()) { - decl = TD; + const auto *CXXRD = type->getAsCXXRecordDecl(); + if (CXXRD && !CXXRD->hasDefinition()) { + decl = CXXRD; } } SetDecl(decl); From b51209a4e02a72506c267ae56c7a272e238eb9fe Mon Sep 17 00:00:00 2001 From: Danilo Piparo Date: Thu, 20 Aug 2026 16:20:41 +0200 Subject: [PATCH 2/4] [meta] Add a test for ROOT-10311 --- core/metacling/test/TClingTests.cxx | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/core/metacling/test/TClingTests.cxx b/core/metacling/test/TClingTests.cxx index 2a54d12864dd3..ec9833264f82e 100644 --- a/core/metacling/test/TClingTests.cxx +++ b/core/metacling/test/TClingTests.cxx @@ -467,4 +467,23 @@ using func0_ret_t = typename ROOT::TypeTraits::CallableTraits:: auto res = gInterpreter->Declare(expression.c_str()); EXPECT_TRUE(res); } -#endif \ No newline at end of file +#endif + +// ROOT-10311 +TEST_F(TClingTests, TClassByCtorName) +{ + auto res = gInterpreter->Declare("namespace TClassByCtorName{class Foo;};"); + EXPECT_TRUE(res); + { + ROOT::TestSupport::CheckDiagsRAII checkDiag; + checkDiag.requiredDiag(kWarning, "TClass::Init", "no dictionary for class TClassByCtorName::Foo is available", false); + EXPECT_TRUE(nullptr != TClass::GetClass("TClassByCtorName::Foo")); + } + const auto *wrongName = "TTree::TTree"; + EXPECT_TRUE(nullptr == TClass::GetClass(wrongName)); + EXPECT_TRUE(nullptr != TClass::GetClass("TTree")); + + std::string classInterpreterName; + gInterpreter->GetInterpreterTypeName(wrongName, classInterpreterName); + EXPECT_STREQ(classInterpreterName.c_str(), ""); +} From 8fe748ab4bb01667575db31ac23228ba65d2a3db Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 26 Aug 2026 13:53:28 -0500 Subject: [PATCH 3/4] [cling] Ignore injected decls. Before this commit, quickFindDecl would 'find' something for `TTree::TTree` which is injected-class-name ([class]p2). --- interpreter/cling/lib/Interpreter/LookupHelper.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interpreter/cling/lib/Interpreter/LookupHelper.cpp b/interpreter/cling/lib/Interpreter/LookupHelper.cpp index 499c9f0631174..1a6433cfd9761 100644 --- a/interpreter/cling/lib/Interpreter/LookupHelper.cpp +++ b/interpreter/cling/lib/Interpreter/LookupHelper.cpp @@ -294,6 +294,14 @@ namespace cling { next = utils::Lookup::Named(&S, declName.substr(last, c + 1 - last), sofar); // If there is an ambiguity, we need to go the long route. if (next == (void *) -1) return false; + if (const auto *RD = dyn_cast_or_null(next); + RD && RD->isInjectedClassName()) { + // We found an injected-class-name, which is not a scope. + // See [class.qual]p2. Not skipping the injected-class-name, would + // lead to a wrong lookup result for "C::C" where C is a class name. + resultDecl = nullptr; + return true; // nothing found + } if (next) { resultDecl = next; } From b68801b6c5976b6cca969b7714a2e0b7f3f7f4f3 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 26 Aug 2026 13:58:22 -0500 Subject: [PATCH 4/4] Revert "[meta] Ctor name lookup is not enough for the class info" This reverts commit 1a29ee1abffbeb5da0a3c3545c43140bee29940c. --- core/metacling/src/TClingClassInfo.cxx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/core/metacling/src/TClingClassInfo.cxx b/core/metacling/src/TClingClassInfo.cxx index 6a703d627cb1a..434996e2cb5aa 100644 --- a/core/metacling/src/TClingClassInfo.cxx +++ b/core/metacling/src/TClingClassInfo.cxx @@ -99,14 +99,9 @@ TClingClassInfo::TClingClassInfo(cling::Interpreter *interp, const char *name, b &type, intantiateTemplate); } } - // The lookup finds the decl if the name corresponds to a namespace or a fully defined - // class; just a type in presence of a forward declaration of a class. - // This code identifies that case and prevents that a class type is found if the name - // of a constructor is passed (see ROOT-10311). if (!decl && type) { - const auto *CXXRD = type->getAsCXXRecordDecl(); - if (CXXRD && !CXXRD->hasDefinition()) { - decl = CXXRD; + if (const auto *TD = type->getAsTagDecl()) { + decl = TD; } } SetDecl(decl);