Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clang vs gcc in abstract class handling in compile time

One of these issues of nlohmann/json opensource library drew my attention.

I have a minimal reproduction of the case that does not compile under few version of desktop gcc (4.8, 4.9, also tried 5+) but compiles well with mac clang and Android ndk's gcc 4.9

#include <limits>

struct base {
    virtual void foo() = 0;
};

int main() {
    (void)numeric_limits<base>::is_signed;
}

GCC is trying to instantiate std::numeric_limits with base class instead of derived:

/usr/include/c++/4.8/limits: In instantiation of 'struct std::numeric_limits<base>': main.cpp:11:94:   required from here
/usr/include/c++/4.8/limits:309:7: error: cannot allocate an object of abstract type 'base'
min() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }

I'm not quite sure if this is a known compiler bug (in case of failure) or feature/relaxed rule (in case of success)

I've tried to work it around with std::is_abstract but it does not help, looks like 'short-circuit' evaluation is not happening in enable_if and error stays the same

My question mainly is not how to fix this for gcc but weather this is compiler bug or code bug


Edit: added "more minimal" example without any standard library dependency:

template <typename T>
struct foo
{
  static T bar();
  static constexpr bool value = true;
};

struct abstract
{
  virtual ~abstract() = 0;
};

int main()
{
  (void) foo<abstract>::value;
}

Compiles on clang 3.9.0, but gcc 7 snapshot emits an error for the invalid return type of foo<abstract>::bar.


Edit2: I'm a bit surprised that my initial question was edited without my consent, was not aware that SO allows that :) Thanks for help though I think it brought a bit of confusion and wrong answers, mainly because text and code were not connected anymore

like image 667
Oleg Bogdanov Avatar asked Nov 05 '16 20:11

Oleg Bogdanov


People also ask

Does Clang compile faster than GCC?

Clang is much faster and uses far less memory than GCC. Clang aims to provide extremely clear and concise diagnostics (error and warning messages), and includes support for expressive diagnostics. GCC's warnings are sometimes acceptable, but are often confusing and it does not support expressive diagnostics.

Is GCC faster than LLVM?

While LLVM's Clang C/C++ compiler was traditionally known for its faster build speeds than GCC, in recent releases of GCC the build speeds have improved and in some areas LLVM/Clang has slowed down with further optimization passes and other work added to its growing code-base.

Is Clang a good compiler?

Clang is not just like any other compiler, it comes with an Infrastructure that allows it to build tools and it can also extend its behaviors easily. The LLVM/Clang source code includes many tools while others are available on the web. Clang can be used as a very good C/C++ parser for building tools.

Is Clang replacing GCC?

Clang is a compiler front end for the C, C++, Objective-C, and Objective-C++ programming languages, as well as the OpenMP, OpenCL, RenderScript, CUDA, and HIP frameworks. It acts as a drop-in replacement for the GNU Compiler Collection (GCC), supporting most of its compilation flags and unofficial language extensions.


1 Answers

No, it is not a bug. It is just a bad test.

Description

The only difference between GCC and clang in this case is the way they process template class functions:

  • GCC: All of them in once.
  • clang: Only the one that has been used.

In our first example, the function min() doesn't get called, and therefore, clang doesn't has a problem with it. GCC, parses all the functions and find out that min() is invalid.

In the second example, the same happens: bar() doesn't get called by anyone and therefore clang is OK about it being ill-formed. But again, GCC, have a problem with it, although hasn't been used anywhere in the program.

A good test

Saying that something is bad is not enough, let's fix it: this example would fail with both GCC and clang with almost the same error (invalid abstract return type ‘base’ or allocating an object of abstract class type 'base').

#include <limits>

struct base {
    virtual void foo() = 0;
};

int main() {
    (void)std::numeric_limits<base>::min();
}
like image 115
Shmuel H. Avatar answered Oct 01 '22 19:10

Shmuel H.