[IO] `TCling::GenerateDictionary` is broken for `RVec<CustomType>`
- [X] Checked for duplicates
Describe the bug
As far as I understand, this should work:
#ifndef TWOINTS
#define TWOINTS
struct TwoInts {
int a, b;
};
#endif
#include <ROOT/RDataFrame.hxx>
#include <TError.h>
#include <TInterpreter.h>
#include <TKey.h>
#include "TwoInts.h"
int main() {
gInterpreter->GenerateDictionary("TwoInts;ROOT::VecOps::RVec<TwoInts>",
"ROOT/RVec.hxx;TwoInts.h");
TFile f("f.root", "recreate");
auto *cl = TClass::GetClass("ROOT::VecOps::RVec<TwoInts>");
R__ASSERT(cl != nullptr);
ROOT::RVec<TwoInts> v{{1, 2}, {3, 4}};
f.WriteObjectAny(&v, cl, "v");
f.Close();
TFile in_f("f.root");
auto *k = in_f.GetKey("v");
auto *obj = static_cast<ROOT::RVec<TwoInts> *>(k->ReadObjectAny(cl));
R__ASSERT(obj != nullptr);
auto &in_v = *obj;
R__ASSERT(in_v[0].a == 1 && in_v[0].b == 2 && in_v[1].a == 3 &&
in_v[1].b == 4);
return 0;
}
But instead produces:
g++ -g -Wall -Wextra -Wpedantic -o "repro" "repro.cpp" $(root-config --cflags --libs)
~/S/w/rootcling_rvec ./repro
/home/blue/Scratchpad/work/rootcling_rvec/AutoDict_TwoInts_2251615068_cxx_ACLiC_dict.cxx:55:61: error: expected ‘)’ before ‘::’ token
55 | static TGenericClassInfo *GenerateInitInstanceLocal(const ::*)
| ~ ^~~
| )
because the autogenerated dictionary code is broken (see the invalid (const ::*).
Setup
ROOT master @ 9f1902c1 . I would not even attempt this with v6.24 or earlier because I/O of RVecs is not well-supported there.
Additional context
https://github.com/root-project/root/blob/9f1902c1d898ec615244f547c0683d0f10820da8/core/metacling/src/TCling.cxx#L742-L745
This is definitely part of the problem: RVec should be treated like an STL class. Axel also pointed out the suspicious:
https://github.com/root-project/root/blob/9f1902c1d898ec615244f547c0683d0f10820da8/core/metacling/src/TCling.cxx#L786-L796
A more minimal reproducer that catches at least some of the problems:
// LinkDef.h
#include <ROOT/RVec.hxx>
#include "TwoInts.h"
#ifdef __CLING__
#pragma link C++ class ROOT::VecOps::RVec<TwoInts>+;
#pragma link C++ class ROOT::VecOps::RVec<TwoInts>::*+;
#endif
// TwoInts.h
#ifndef TWOINTS
#define TWOINTS
struct TwoInts {
int a, b;
};
#endif
and rootcling "twoints_dict.cxx" LinkDef.h produces invalid C++ in twoints_dict.cxx.
The line #pragma link C++ class ROOT::VecOps::RVec<TwoInts>::*+; is required to trigger the problematic behavior (and TCling::GenerateDictionary puts it in the auto-dicts).
This is still a problem in v6.26.
I was just hit by this again after forgetting about it again :smile: ping @pcanal @Axel-Naumann :grimacing:
@devajithvs @vgvassilev do you have a hint?