Skip to content

Commit ec01d4e

Browse files
authored
[win] Fix std::complex on Windows (#20492)
* [win] Fix `std::complex` on Windows This PR fixes #20312 - In TCling::CreateListOfBaseClasses, ignore the `std::_Complex_base` base class - Since the order of execution of function arguments are not guarantees, don't pass TRandom3 methods as function arguments This fixes the `execreadcomplex.C` and `execwritecomplex.C` macros - Code formatting * Ignore the base class inconditionally * clang-format
1 parent 6859d10 commit ec01d4e

File tree

6 files changed

+70
-54
lines changed

6 files changed

+70
-54
lines changed

core/metacling/src/TCling.cxx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4433,6 +4433,11 @@ void TCling::CreateListOfBaseClasses(TClass *cl) const
44334433
if (cl->fBase) {
44344434
return;
44354435
}
4436+
// Ignore the base class (e.g. `std::_Complex_base` on Windows)
4437+
if (TClassEdit::GetComplexType(cl->GetName()) != TClassEdit::EComplexType::kNone) {
4438+
cl->fBase = new TList();
4439+
return;
4440+
}
44364441
TClingClassInfo *tci = (TClingClassInfo *)cl->GetClassInfo();
44374442
if (!tci) return;
44384443
TClingBaseClassInfo t(GetInterpreterImpl(), tci);

roottest/root/io/complex/CMakeLists.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,22 @@ ROOTTEST_GENERATE_REFLEX_DICTIONARY(classWithComplex
66
ROOTTEST_ADD_TEST(writeClassWithComplex
77
MACRO execwriteClassWithComplex.C
88
OUTREF execwriteClassWithComplex.ref
9-
${WILLFAIL_ON_WIN32}
109
FIXTURES_REQUIRED root-io-complex-dict-fixture
1110
FIXTURES_SETUP root-io-complex-writeClassWithComplex-fixture)
1211

1312
ROOTTEST_ADD_TEST(readClassWithComplex
1413
MACRO execreadClassWithComplex.C
1514
OUTREF execreadClassWithComplex.ref
16-
${WILLFAIL_ON_WIN32}
1715
FIXTURES_REQUIRED root-io-complex-writeClassWithComplex-fixture)
1816

1917

2018
ROOTTEST_ADD_TEST(writecomplex
2119
MACRO execwritecomplex.C
22-
${WILLFAIL_ON_WIN32}
2320
OUTREF execwritecomplex.ref
2421
FIXTURES_SETUP root-io-complex-writecomplex-fixture)
2522

2623
ROOTTEST_ADD_TEST(readcomplex
2724
COPY_TO_BUILDDIR complexOfilekubuntuROOT5.root complexOfilekubuntuROOT6.root complexOfileslc6ROOT5.xml complexOfilekubuntuROOT5.xml complexOfilekubuntuROOT6.xml complexOfileslc6ROOT5.root
2825
MACRO execreadcomplex.C
2926
OUTREF execreadcomplex.ref
30-
${WILLFAIL_ON_WIN32}
3127
FIXTURES_REQUIRED root-io-complex-writecomplex-fixture)

roottest/root/io/complex/execreadcomplex.C

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
// This macro must be v5/v6 executable!
22

3-
void compareValues(const char* filename,
4-
complex<float> cFloat, complex<float> cFloatRef,
5-
complex<double> cDouble, complex<double> cDoubleRef){
3+
void compareValues(const char *filename, const char *where, complex<float> cFloat, complex<float> cFloatRef,
4+
complex<double> cDouble, complex<double> cDoubleRef)
5+
{
66
if (cFloatRef != cFloat) {
7-
cout << "ERROR complex<float> on file " << filename << " numbers differ! Reference: " << cFloatRef << " on disk " << cFloat << endl;
7+
cout << "ERROR complex<float> on file " << filename << " numbers differ for " << where
8+
<< " ! Reference: " << cFloatRef << " on disk " << cFloat << endl;
89
}
910
if (cDoubleRef != cDouble) {
10-
cout << "ERROR complex<double> on file " << filename << " numbers differ! Reference: " << cDoubleRef << " on disk " << cDouble << endl;
11+
cout << "ERROR complex<double> on file " << filename << " numbers differ for " << where
12+
<< " ! Reference: " << cDoubleRef << " on disk " << cDouble << endl;
1113
}
12-
1314
}
1415

1516
void readcomplex(const std::string base)
@@ -46,8 +47,14 @@ void readcomplex(const std::string base)
4647
for (int j = 0; j < nIters; ++j) {
4748

4849
// Re-generate values
49-
std::complex<float> cFloatRef(rndm.Uniform(theMin, theMax), rndm.Uniform(theMin, theMax));
50-
std::complex<double> cDoubleRef(rndm.Uniform(theMin, theMax), rndm.Uniform(theMin, theMax));
50+
// Since the order of execution of function arguments are not guarantees by the standard,
51+
// don't pass TRandom3 methods as function arguments, to avoid potential cross-platform differences
52+
auto rnd1 = rndm.Uniform(theMin, theMax);
53+
auto rnd2 = rndm.Uniform(theMin, theMax);
54+
auto rnd3 = rndm.Uniform(theMin, theMax);
55+
auto rnd4 = rndm.Uniform(theMin, theMax);
56+
std::complex<float> cFloatRef(rnd1, rnd2);
57+
std::complex<double> cDoubleRef(rnd3, rnd4);
5158

5259
// read them
5360
TString cFloatName(TString::Format("cFloat_%i", j));
@@ -63,42 +70,44 @@ void readcomplex(const std::string base)
6370
cout << "ERROR Cannot get " << cDoubleName << " from file " << ifilename << endl;
6471
continue;
6572
}
66-
6773
// compare them bit-by-bit
68-
compareValues(ifilename, *cFloatPtr, cFloatRef, *cDoublePtr, cDoubleRef);
69-
74+
compareValues(ifilename, TString::Format("cFloat/cDouble #%i", j), *cFloatPtr, cFloatRef, *cDoublePtr,
75+
cDoubleRef);
7076
}
7177

7278
if (iFile != 1) {
73-
7479
// Now the tree
7580
TTreeReader reader ("t",ifile);
7681
TTreeReaderValue<complex<float>> cFloat_split(reader, "cFloat_split");
7782
TTreeReaderValue<complex<float>> cFloat(reader, "cFloat");
7883
TTreeReaderValue<complex<double>> cDouble_split(reader, "cDouble_split");
7984
TTreeReaderValue<complex<double>> cDouble(reader, "cDouble");
8085

86+
int e = 0;
8187
while (reader.Next()) {
82-
std::complex<float> cFloatn(rndm.Uniform(theMin,theMax),rndm.Uniform(theMin,theMax));
83-
std::complex<double> cDoublen(rndm.Uniform(theMin,theMax),rndm.Uniform(theMin,theMax));
84-
compareValues(ifilename, *cFloat_split, cFloatn, *cDouble_split, cDoublen);
85-
compareValues(ifilename, *cFloat, cFloatn, *cDouble, cDoublen);
88+
auto rnd11 = rndm.Uniform(theMin, theMax);
89+
auto rnd12 = rndm.Uniform(theMin, theMax);
90+
auto rnd13 = rndm.Uniform(theMin, theMax);
91+
auto rnd14 = rndm.Uniform(theMin, theMax);
92+
std::complex<float> cFloatn(rnd11, rnd12);
93+
std::complex<double> cDoublen(rnd13, rnd14);
94+
compareValues(ifilename, TString::Format("Split branch entry #%i", e), *cFloat_split, cFloatn,
95+
*cDouble_split, cDoublen);
96+
compareValues(ifilename, TString::Format("Streamed branch entry #%i", e), *cFloat, cFloatn, *cDouble,
97+
cDoublen);
98+
++e;
8699
}
87-
88100
}
89-
90101
}
91102
}
92103

93104
void execreadcomplex()
94105
{
95-
96106
// Files produced on this very platform
97107
readcomplex("complexOfileROOT6");
98108

99109
// A collection of files coming for elsewhere
100110
readcomplex("complexOfilekubuntuROOT5");
101111
readcomplex("complexOfilekubuntuROOT6");
102112
readcomplex("complexOfileslc6ROOT5");
103-
104113
}
Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
// This macro must be v5/v6 executable!
22

3-
void writecomplex(const std::string base){
4-
3+
void writecomplex(const std::string base)
4+
{
55
const int nentries = 1000;
66

77
const double theMax = 1000.;
88
const double theMin = -theMax;
99

1010
// The two formats
1111
std::string rVersion = "ROOT6";
12-
if (gROOT->GetVersionInt()<60000)
12+
if (gROOT->GetVersionInt() < 60000)
1313
rVersion = "ROOT5";
1414

1515
std::vector<string> ofileNames;
16-
ofileNames.push_back(base+rVersion+".xml");
17-
ofileNames.push_back(base+rVersion+".root");
16+
ofileNames.push_back(base + rVersion + ".xml");
17+
ofileNames.push_back(base + rVersion + ".root");
1818

19-
for (int iFile=0;iFile<ofileNames.size();++iFile){
19+
for (int iFile = 0; iFile < ofileNames.size(); ++iFile) {
2020

2121
const char* ofileName = ofileNames[iFile].c_str();
2222

@@ -27,36 +27,47 @@ void writecomplex(const std::string base){
2727
TRandom3 rndm(1);
2828

2929
// Write nentries random complex per type
30-
for (int j=0;j<nentries;++j){
31-
std::complex<float> cFloatrw(rndm.Uniform(theMin,theMax),rndm.Uniform(theMin,theMax));
32-
std::complex<double> cDoublerw(rndm.Uniform(theMin,theMax),rndm.Uniform(theMin,theMax));
30+
for (int j = 0; j < nentries; ++j) {
31+
// Since the order of execution of function arguments are not guarantees by the standard,
32+
// don't pass TRandom3 methods as function arguments, to avoid potential cross-platform differences
33+
auto rnd1 = rndm.Uniform(theMin, theMax);
34+
auto rnd2 = rndm.Uniform(theMin, theMax);
35+
auto rnd3 = rndm.Uniform(theMin, theMax);
36+
auto rnd4 = rndm.Uniform(theMin, theMax);
37+
std::complex<float> cFloatrw(rnd1, rnd2);
38+
std::complex<double> cDoublerw(rnd3, rnd4);
3339

34-
ofile->WriteObjectAny(&cFloatrw,"complex<float>",TString::Format("cFloat_%i",j));
35-
ofile->WriteObjectAny(&cDoublerw,"complex<double>",TString::Format("cDouble_%i",j));
40+
ofile->WriteObjectAny(&cFloatrw, "complex<float>", TString::Format("cFloat_%i", j));
41+
ofile->WriteObjectAny(&cDoublerw, "complex<double>", TString::Format("cDouble_%i", j));
3642
}
3743

3844
if (iFile != 0) { // tree not supported on xml
3945

4046
// Now write a tree with nentries events with one branch per type, split and unsplit
41-
std::complex<float>* cFloat = new std::complex<float>(0.f,0.f);
42-
std::complex<double>* cDouble = new std::complex<double>(0.,0.);
43-
TTree t("t","Test Tree");
44-
t.Branch("cFloat_split", &cFloat,16000,99);
45-
t.Branch("cFloat", &cFloat,16000,0);
46-
t.Branch("cDouble_split", &cDouble,16000,99);
47-
t.Branch("cDouble", &cDouble,16000,0);
48-
for (int j=0;j<nentries;++j){
49-
std::complex<float> cFloatVol(rndm.Uniform(theMin,theMax),rndm.Uniform(theMin,theMax));
50-
std::complex<double> cDoubleVol(rndm.Uniform(theMin,theMax),rndm.Uniform(theMin,theMax));
51-
*cFloat=cFloatVol;
52-
*cDouble=cDoubleVol;
47+
std::complex<float> *cFloat = new std::complex<float>(0.f, 0.f);
48+
std::complex<double> *cDouble = new std::complex<double>(0., 0.);
49+
TTree t("t", "Test Tree");
50+
t.Branch("cFloat_split", &cFloat, 16000, 99);
51+
t.Branch("cFloat", &cFloat, 16000, 0);
52+
t.Branch("cDouble_split", &cDouble, 16000, 99);
53+
t.Branch("cDouble", &cDouble, 16000, 0);
54+
for (int j = 0; j < nentries; ++j) {
55+
auto rnd11 = rndm.Uniform(theMin, theMax);
56+
auto rnd12 = rndm.Uniform(theMin, theMax);
57+
auto rnd13 = rndm.Uniform(theMin, theMax);
58+
auto rnd14 = rndm.Uniform(theMin, theMax);
59+
std::complex<float> cFloatVol(rnd11, rnd12);
60+
std::complex<double> cDoubleVol(rnd13, rnd14);
61+
*cFloat = cFloatVol;
62+
*cDouble = cDoubleVol;
5363
t.Fill();
5464
}
5565
t.Write();
5666
}
5767
}
5868
}
5969

60-
void execwritecomplex(){
70+
void execwritecomplex()
71+
{
6172
writecomplex("complexOfile");
6273
}

roottest/root/io/newstl/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ endif()
5252
ROOTTEST_ADD_TEST(ComplexTest
5353
MACRO runComplexTest.C
5454
ROOTEXE_OPTS ${_complextest_load}
55-
OUTREF ComplexTest${ref_suffix}
55+
OUTREF ComplexTest.ref
5656
FIXTURES_REQUIRED root-io-newstl-ComplexTest_h-fixture)
5757

5858
ROOTTEST_ADD_TEST(SampleFile

roottest/root/io/newstl/ComplexTest.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,4 @@ class Test: public TObject
2424
ClassDefOverride(Test, 1);
2525
};
2626

27-
#ifdef __ROOTCLING__
28-
#pragma link C++ class std::complex<double>+;
29-
#pragma link C++ class Test+;
30-
#endif
31-
3227
#endif /* Test_hh */

0 commit comments

Comments
 (0)