Skip to content

Commit d536a4f

Browse files
authored
Fix static thread_local issue with GCC (#93)
* Workaround to avoid GCC bug Avoid `redefinition of ‘bool __tls_guard’` GCC build error. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66944.
1 parent 656d23e commit d536a4f

File tree

4 files changed

+54
-9
lines changed

4 files changed

+54
-9
lines changed

include/cppad/cg/cg.hpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -267,12 +267,15 @@ class CG {
267267
*/
268268
template<class Base>
269269
struct CGOStreamFunc {
270-
static thread_local std::function<std::ostream& (std::ostream&, const CG<Base>&)> FUNC;
270+
// Because of a GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66944)
271+
// FUNC_OBJ can't be a CGOStreamFunc static member.
272+
// Instead, we store it as CGOStreamFunc::FUNC method static variable.
273+
static std::function<std::ostream& (std::ostream&, const CG<Base>&)>& FUNC () {
274+
static thread_local std::function<std::ostream& (std::ostream&, const CG<Base>&)> FUNC_OBJ = nullptr;
275+
return FUNC_OBJ;
276+
}
271277
};
272278

273-
template<class Base>
274-
thread_local std::function<std::ostream& (std::ostream&, const CG<Base>&)> CGOStreamFunc<Base>::FUNC = nullptr;
275-
276279
/**
277280
* Output stream operator for CG objects.
278281
* Default behavior can be overridden using CGOStreamFunc::FUN.
@@ -282,8 +285,8 @@ inline std::ostream& operator<<(
282285
std::ostream& os, //< stream to write to
283286
const CG<Base>& v//< vector that is output
284287
) {
285-
if(CGOStreamFunc<Base>::FUNC != nullptr) {
286-
return CGOStreamFunc<Base>::FUNC(os, v);
288+
if(CGOStreamFunc<Base>::FUNC() != nullptr) {
289+
return CGOStreamFunc<Base>::FUNC()(os, v);
287290
}
288291

289292
if (v.isParameter()) {

include/cppad/cg/operation_node_name_streambuf.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,16 @@ class OperationNodeNameStreambuf : public std::streambuf {
4444
if (BUF != nullptr) {
4545
throw CGException("Only one OperationNodeNameStreambuf can exist at a time in each thread");
4646
}
47-
if (CGOStreamFunc<Base>::FUNC != nullptr) {
47+
if (CGOStreamFunc<Base>::FUNC() != nullptr) {
4848
throw CGException("CGOStreamFunc<Base>::FUNC already defined in this thread");
4949
}
5050
BUF = this;
51-
CGOStreamFunc<Base>::FUNC = registerNode;
51+
CGOStreamFunc<Base>::FUNC() = registerNode;
5252
}
5353

5454
virtual ~OperationNodeNameStreambuf() {
5555
BUF = nullptr;
56-
CGOStreamFunc<Base>::FUNC = nullptr;
56+
CGOStreamFunc<Base>::FUNC() = nullptr;
5757
}
5858

5959
std::streamsize xsputn(const char_type* s,

test/cppad/cg/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_cppadcg_test(inputstream.cpp)
2222
add_cppadcg_test(temporary.cpp)
2323
add_cppadcg_test(mult_sparsity_pattern.cpp)
2424
add_cppadcg_test(multi_object_1.cpp multi_object.cpp)
25+
add_cppadcg_test(gcc_build_issue.cpp)
2526

2627
ADD_SUBDIRECTORY(extra)
2728
ADD_SUBDIRECTORY(operations)

test/cppad/cg/gcc_build_issue.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* --------------------------------------------------------------------------
2+
* CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
3+
* Copyright (C) 2012 Joris Vaillant
4+
*
5+
* CppADCodeGen is distributed under multiple licenses:
6+
*
7+
* - Eclipse Public License Version 1.0 (EPL1), and
8+
* - GNU General Public License Version 3 (GPL3).
9+
*
10+
* EPL1 terms and conditions can be found in the file "epl-v10.txt", while
11+
* terms and conditions for the GPL3 can be found in the file "gpl3.txt".
12+
* ----------------------------------------------------------------------------
13+
* Author: Joris Vaillant
14+
*/
15+
#include "CppADCGTest.hpp"
16+
17+
using namespace CppAD;
18+
using namespace CppAD::cg;
19+
20+
// Test GCC compilation bug issue: https://github.com/joaoleal/CppADCodeGen/issues/92
21+
// This test only have to build to pass
22+
23+
struct A {};
24+
struct B {};
25+
26+
template <typename T>
27+
struct Wrapper {
28+
virtual void foo() {
29+
v.FUNC();
30+
}
31+
CppAD::cg::CGOStreamFunc<T> v;
32+
};
33+
34+
int main() {
35+
};
36+
37+
TEST_F(CppADCGTest, TestGCCBuildIssue) {
38+
Wrapper<A> a;
39+
Wrapper<B> b;
40+
a.v.FUNC();
41+
}

0 commit comments

Comments
 (0)