Skip to content

[core] Fix improper name normalization in KeepNParams#21567

Merged
silverweed merged 2 commits intoroot-project:masterfrom
silverweed:map_alloc_classedit
Mar 18, 2026
Merged

[core] Fix improper name normalization in KeepNParams#21567
silverweed merged 2 commits intoroot-project:masterfrom
silverweed:map_alloc_classedit

Conversation

@silverweed
Copy link
Contributor

@silverweed silverweed commented Mar 11, 2026

The algorithm was not recording any default arguments into argsToKeep, but it actually needs to keep them as long as they are followed by a non-default argument.

This would cause issues such as this:

// std::less<int> is a default argument, but MyAlloc is not 
using MyMap = std::map<int, int, std::less<int>, MyAlloc>;

TClass::GetClass("MyMap")->GetName() // prints "map<int,int,MyAlloc>" !

NOTE

I am not familiar with the Cling codebase so this fix might be missing something or be wrong for some other reason. The TClassEdit tests are passing, at least, but I kindly ask Cling experts to scrutinize this change thoroughly.

Checklist:

  • tested changes locally
  • updated the docs (if necessary)

This PR fixes #

@silverweed silverweed force-pushed the map_alloc_classedit branch from aa7739b to 0fd3044 Compare March 11, 2026 11:03
@github-actions
Copy link

github-actions bot commented Mar 11, 2026

Test Results

    21 files      21 suites   3d 5h 31m 31s ⏱️
 3 834 tests  3 833 ✅ 1 💤 0 ❌
72 851 runs  72 842 ✅ 9 💤 0 ❌

Results for commit 2c5a386.

♻️ This comment has been updated with latest results.

@silverweed silverweed force-pushed the map_alloc_classedit branch from 0fd3044 to c37967c Compare March 11, 2026 16:03
@silverweed
Copy link
Contributor Author

Test fails on mac with:

2026-03-11T17:37:05.5216310Z Expected equality of these values:
2026-03-11T17:37:05.5219690Z   "std::map<int,int>"
2026-03-11T17:37:05.5219810Z   n.c_str()
2026-03-11T17:37:05.5220220Z     Which is: "map<int,int>"

which is concerning...

The algorithm was not recording any default arguments into argsToKeep,
but it actually needs to keep them as long as they are followed by a
non-default argument.

This would cause issues such as this:

// std::less<int> is a default argument, but MyAlloc is not
using MyMap = std::map<int, int, std::less<int>, MyAlloc>;

TClass::GetClass("MyMap")->GetName() # prints "map<int,int,MyAlloc>" !
@silverweed silverweed force-pushed the map_alloc_classedit branch from c37967c to f4e0d07 Compare March 12, 2026 07:42
@pcanal
Copy link
Member

pcanal commented Mar 17, 2026

Note, the new test shows a behavior different between Linux and MacOS for the selected template instantiation.

Difference between Linux/runtime_cxxmodules and macOS/runtime_cxxmodules execution of

using MyMapDefault = map<int,int,std::less<int>,std::allocator<std::pair<const int,int>>>;
std::string n;
TClassEdit::GetNormalizedName(n, "MyMapDefault");

On linux/runtime_cxxmodules we get the incorrect: std::map<int, int>
on MacOS/runtime_cxxmodules, I get the correct: map<int, int>

Inside of TClassEdit::GetNormalizedName, in both case, the TClassEdit::TSplitType stage
returns std::map<int, int>. When the name passed has no alias (eg. directly std::map<iny, int>),
the TClassEdit::TSplitType stage directly return the normalized name (map<int, int>)

On linux the stage GetPartiallyDesugaredNameWithScopeHandling does not provide an update
On MacOS the stage GetPartiallyDesugaredNameWithScopeHandling provides the correct name.
This is ‘due’ to TMetaUtils::GetNormalizedType on line TClingUtils.cxx:654 returning
a type that is seen as different from the input and thus triggers a printing stage.
(on linux the input and output type evaluate to equal).

It seems that the differences is the fact that in the ‘they are not equal’ case, the
type is described inside a pcm (see below, ClassTemplateDecl … imported in std.std.map hidden map.

It is not yet determined why this difference exists but could exist in other circumstances.

So let’s explore why TClassEdit::TSplitType get the name ‘wrong’ when passed an alias.

And the following patch cures the symptoms:

diff --git a/core/foundation/src/TClassEdit.cxx b/core/foundation/src/TClassEdit.cxx
index 4835cebace9..8b783698748 100644
--- a/core/foundation/src/TClassEdit.cxx
+++ b/core/foundation/src/TClassEdit.cxx
@@ -454,13 +454,13 @@ void TClassEdit::TSplitType::ShortType(std::string &answ, int mode)
    //   do the same for all inside
    for (int i=1;i<narg; i++) {
       if (!strchr(fElements[i].c_str(),'<')) {
+         if (mode&kResolveTypedef) {
+            fElements[i] = ResolveTypedef(fElements[i].c_str(),true);
+         }
          if (mode&kDropStd) {
             unsigned int offset = (0==strncmp("const ",fElements[i].c_str(),6)) ? 6 : 0;
             RemoveStd( fElements[i], offset );
          }
-         if (mode&kResolveTypedef) {
-            fElements[i] = ResolveTypedef(fElements[i].c_str(),true);
-         }
          continue;
       }
       fElements[i] = TClassEdit::ShortType(fElements[i].c_str(),mode | TClassEdit::kKeepOuterConst);
cmslpc-el9-heavy01:src (issue-19798) pcanal$ 

On MacOS:

(lldb) p t.dump()
ElaboratedType 0xc21e256f0 'std::map<int, int>' sugar
`-TemplateSpecializationType 0xc21e25690 'map<int, int>' sugar
  |-name: 'std::map' qualified
  | |-NestedNameSpecifier Namespace 0xc22376b90 'std'
  | `-ClassTemplateDecl 0xc21d5ffa8 prev 0xc21d61930  imported in std.std.map hidden map
  |-TemplateArgument type 'int'
  | `-BuiltinType 0xc22940110 'int'
  |-TemplateArgument type 'int'
  | `-BuiltinType 0xc22940110 'int'
  `-RecordType 0xc21d65970 'class std::map<int, int>'
    `-ClassTemplateSpecialization 0xc21d65830 'map'

On Linux:

(gdb) p t.dump()
ElaboratedType 0x1ac4680 'std::map<int, int>' sugar
`-TemplateSpecializationType 0x1ac4620 'map<int, int>' sugar map
  |-TemplateArgument type 'int'
  | `-BuiltinType 0x54f870 'int'
  |-TemplateArgument type 'int'
  | `-BuiltinType 0x54f870 'int'
  `-RecordType 0x1728640 'class std::map<int, int>'
    `-ClassTemplateSpecialization 0x17284f0 'map'

@silverweed
Copy link
Contributor Author

@pcanal thanks for the investigation! I updated the PR with your patch as well as the wrong test.

@silverweed silverweed force-pushed the map_alloc_classedit branch from 37b67b8 to 2c5a386 Compare March 18, 2026 07:50
Copy link
Member

@pcanal pcanal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

@silverweed silverweed merged commit 30960ee into root-project:master Mar 18, 2026
28 of 30 checks passed
@silverweed silverweed deleted the map_alloc_classedit branch March 18, 2026 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants