title: Using clang++, -fvisibility=hidden, and typeinfo, and type-erasure
body: <p>This is a scaled down version of a problem I am facing with clang++ on Mac OS X.  This was seriously edited to better reflect the genuine problem (the first attempt to describe the issue was not exhibiting the problem).</p>
  
  <h1>The failure</h1>
  
  <p>I have this big piece of software in C++ with a large set of symbols in the object files, so I'm using <code>-fvisibility=hidden</code> to keep my symbol tables small.  It is well known that in such a case one must pay extra attention to the vtables, and I suppose I face this problem.  I don't know however, how to address it elegantly in a way that pleases both gcc and clang.</p>
  
  <p>Consider a <code>base</code> class which features a down-casting operator, <code>as</code>, and a <code>derived</code> class template, that contains some payload.  The pair <code>base</code>/<code>derived&lt;T&gt;</code> is used to implement type-erasure:</p>
  
  <pre><code>// foo.hh
  
  #define API __attribute__((visibility("default")))
  
  struct API base
  {
    virtual ~base() {}
  
    template &lt;typename T&gt;
    const T&amp; as() const
    {
      return dynamic_cast&lt;const T&amp;&gt;(*this);
    }
  };
  
  template &lt;typename T&gt;
  struct API derived: base
  {};
  
  struct payload {}; // *not* flagged as "default visibility".
  
  API void bar(const base&amp; b);
  API void baz(const base&amp; b);
  </code></pre>
  
  <p>Then I have two different compilation units that provide a similar service, which I can approximate as twice the same feature: down-casting from <code>base</code> to <code>derive&lt;payload&gt;</code>:</p>
  
  <pre><code>// bar.cc
  #include "foo.hh"
  void bar(const base&amp; b)
  {
    b.as&lt;derived&lt;payload&gt;&gt;();
  }
  </code></pre>
  
  <p>and</p>
  
  <pre><code>// baz.cc
  #include "foo.hh"
  void baz(const base&amp; b)
  {
    b.as&lt;derived&lt;payload&gt;&gt;();
  }
  </code></pre>
  
  <p>From these two files, I build a dylib.  Here is the <code>main</code> function, calling these functions from the dylib:</p>
  
  <pre><code>// main.cc
  #include &lt;stdexcept&gt;
  #include &lt;iostream&gt;
  #include "foo.hh"
  
  int main()
  try
    {
      derived&lt;payload&gt; d;
      bar(d);
      baz(d);
    }
  catch (std::exception&amp; e)
    {
      std::cerr &lt;&lt; e.what() &lt;&lt; std::endl;
    }
  </code></pre>
  
  <p>Finally, a Makefile to compile and link everybody.  Nothing special here, except, of course, <code>-fvisibility=hidden</code>.</p>
  
  <pre><code>CXX = clang++
  CXXFLAGS = -std=c++11 -fvisibility=hidden
  
  all: main
  
  main: main.o bar.dylib baz.dylib
      $(CXX) -o $@ $^
  
  %.dylib: %.cc foo.hh
      $(CXX) $(CXXFLAGS) -shared -o $@ $&lt;
  
  %.o: %.cc foo.hh
      $(CXX) $(CXXFLAGS) -c -o $@ $&lt;
  
  clean:
      rm -f main main.o bar.o baz.o bar.dylib baz.dylib libba.dylib
  </code></pre>
  
  <p>The run succeeds with gcc (4.8) on OS X:</p>
  
  <pre><code>$ make clean &amp;&amp; make CXX=g++-mp-4.8 &amp;&amp; ./main 
  rm -f main main.o bar.o baz.o bar.dylib baz.dylib libba.dylib
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -c main.cc -o main.o
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -shared -o bar.dylib bar.cc
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -shared -o baz.dylib baz.cc
  g++-mp-4.8 -o main main.o bar.dylib baz.dylib
  </code></pre>
  
  <p>However with clang (3.4), this fails:</p>
  
  <pre><code>$ make clean &amp;&amp; make CXX=clang++-mp-3.4 &amp;&amp; ./main
  rm -f main main.o bar.o baz.o bar.dylib baz.dylib libba.dylib
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -c main.cc -o main.o
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -shared -o bar.dylib bar.cc
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -shared -o baz.dylib baz.cc
  clang++-mp-3.4 -o main main.o bar.dylib baz.dylib
  std::bad_cast
  </code></pre>
  
  <p>However it works if I use</p>
  
  <pre><code>struct API payload {};
  </code></pre>
  
  <p>but I do not want to expose the payload type.  So my questions are:</p>
  
  <ol>
  <li>why are GCC and Clang different here?</li>
  <li>is it <em>really</em> working with GCC, or I was just "lucky" in my use of undefined behavior?</li>
  <li>do I have a means to avoid making <code>payload</code> go public with Clang++?</li>
  </ol>
  
  <p>Thanks in advance.</p>
  
  <h1>Type equality of visible class templates with invisible type parameters (EDIT)</h1>
  
  <p>I have now a better understanding of what is happening.  It is appears that both GCC <em>and</em> clang require both the class template and its parameter to be visible (in the ELF sense) to build a unique type.  If you change the <code>bar.cc</code> and <code>baz.cc</code> functions as follows:</p>
  
  <pre><code>// bar.cc
  #include "foo.hh"
  void bar(const base&amp; b)
  {
    std::cerr
      &lt;&lt; "bar value: " &lt;&lt; &amp;typeid(b) &lt;&lt; std::endl
      &lt;&lt; "bar type:  " &lt;&lt; &amp;typeid(derived&lt;payload&gt;) &lt;&lt; std::endl
      &lt;&lt; "bar equal: " &lt;&lt; (typeid(b) == typeid(derived&lt;payload&gt;)) &lt;&lt; std::endl;
    b.as&lt;derived&lt;payload&gt;&gt;();
  }
  </code></pre>
  
  <p>and <em>if</em> you make <code>payload</code> visible too:</p>
  
  <pre><code>struct API payload {};
  </code></pre>
  
  <p>then you will see that both GCC and Clang will succeed:</p>
  
  <pre><code>$ make clean &amp;&amp; make CXX=g++-mp-4.8
  rm -f main main.o bar.o baz.o bar.dylib baz.dylib libba.dylib
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -c -o main.o main.cc
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -shared -o bar.dylib bar.cc
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -shared -o baz.dylib baz.cc
  ./g++-mp-4.8 -o main main.o bar.dylib baz.dylib
  $ ./main
  bar value: 0x106785140
  bar type:  0x106785140
  bar equal: 1
  baz value: 0x106785140
  baz type:  0x106785140
  baz equal: 1
  
  $ make clean &amp;&amp; make CXX=clang++-mp-3.4
  rm -f main main.o bar.o baz.o bar.dylib baz.dylib libba.dylib
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -c -o main.o main.cc
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -shared -o bar.dylib bar.cc
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -shared -o baz.dylib baz.cc
  clang++-mp-3.4 -o main main.o bar.dylib baz.dylib
  $ ./main
  bar value: 0x10a6d5110
  bar type:  0x10a6d5110
  bar equal: 1
  baz value: 0x10a6d5110
  baz type:  0x10a6d5110
  baz equal: 1
  </code></pre>
  
  <p>Type equality is easy to check, there is actually a single instantiation of the type, as witnessed by its unique address.</p>
  
  <p>However, if you remove the visible attribute from <code>payload</code>:</p>
  
  <pre><code>struct payload {};
  </code></pre>
  
  <p>then you get with GCC:</p>
  
  <pre><code>$ make clean &amp;&amp; make CXX=g++-mp-4.8
  rm -f main main.o bar.o baz.o bar.dylib baz.dylib libba.dylib
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -c -o main.o main.cc
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -shared -o bar.dylib bar.cc
  g++-mp-4.8 -std=c++11 -fvisibility=hidden -shared -o baz.dylib baz.cc
  g++-mp-4.8 -o main main.o bar.dylib baz.dylib
  $ ./main
  bar value: 0x10faea120
  bar type:  0x10faf1090
  bar equal: 1
  baz value: 0x10faea120
  baz type:  0x10fafb090
  baz equal: 1
  </code></pre>
  
  <p>Now there are several instantiation of the type <code>derived&lt;payload&gt;</code> (as witnessed by the three different addresses), but GCC sees these types are equal, and (of course) the two <code>dynamic_cast</code> pass.</p>
  
  <p>In the case of clang, it's different:</p>
  
  <pre><code>$ make clean &amp;&amp; make CXX=clang++-mp-3.4
  rm -f main main.o bar.o baz.o bar.dylib baz.dylib libba.dylib
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -c -o main.o main.cc
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -shared -o bar.dylib bar.cc
  clang++-mp-3.4 -std=c++11 -fvisibility=hidden -shared -o baz.dylib baz.cc
  .clang++-mp-3.4 -o main main.o bar.dylib baz.dylib
  $ ./main
  bar value: 0x1012ae0f0
  bar type:  0x1012b3090
  bar equal: 0
  std::bad_cast
  </code></pre>
  
  <p>There are also three instantiations of the type (removing the failing <code>dynamic_cast</code> does show that there are three), but this time, they are not equal, and the <code>dynamic_cast</code> (of course) fails.</p>
  
  <p>Now the question turns into:
   1. is this difference between both compilers wanted by their authors
   2. if not, what is "expected" behavior between both</p>
  
  <p>I prefer GCC's semantics, as it allows to really implement type-erasure without any need to expose publicly the wrapped types.</p>