The takeaways of GCC optimization

GCC optimization is a good document but a little verbose. I summarize the takeaways of it in this post:

(1) Use -march to generate the optimized code for specified CPU. E.g., -march=native. But beware that the code will not have backwards compatibility for older/different CPUs.

(2) -O2 is recommended. But if play with cmake, “cmake -DCMAKE_BUILD_TYPE=Release ..” will use -O3 to compile code. At least from my own experience,-O3 should be OK.

(3) -pipe has no effect on the generated code but makes compilation fast. If the system has enough memory, use it.

So the best method of compiling code using gcc should be:

# gcc -march=native -O2 -pipe test.c -o test

Or use -O3 instead of -O2? I dunno, choose -O2 or -O3 at your own risk.

Different RVO behaviors between gcc and clang

Regarding RVO (Return Value Optimization), I think this video gives a real good explanation. Let’s cut to the chase. Check following code:

# cat rvo.cpp
#include <iostream>

class Foo
{
public:
        Foo(){std::cout << "Foo default constructor!\n";}
        ~Foo(){std::cout << "Foo destructor!\n";}
        Foo(const Foo&){std::cout << "Foo copy constructor!\n";}
        Foo& operator=(const Foo&){std::cout << "Foo assignment!\n"; return *this;}
        Foo(const Foo&&){std::cout << "Foo move constructor!\n";}
        Foo& operator=(const Foo&&){std::cout << "Foo move assignment!\n"; return *this;}
};

Foo func(bool flag)
{
        Foo temp;
        if (flag)
        {
                std::cout << "if\n";
        }
        else
        {
                std::cout << "else\n";
        }
        return temp;
}

int main()
{
        auto f = func(true);
        return 0;
}

On my Arch Linux platform, gcc version is 8.2.1 and clang version is 8.0.0. I tried to use -std=c++11, -std=c++14, -std=c++17 and -std=c++2a for both compilers, all generated same output:

Foo default constructor!
if
Foo destructor!

So both compilers are clever enough to realize there is no need to create “Foo temp” variable (please refer Small examples show copy elision in C++). Modify the func a little:

Foo func(bool flag)
{
        if (flag)
        {
                Foo temp;
                std::cout << "if\n";
                return temp;
        }
        else
        {
                Foo temp;
                std::cout << "else\n";
                return temp;
        }
}

This time, For clang compiler (All four compiling options: -std=c++11, -std=c++14, -std=c++17 and -std=c++2a), the program generated output as same as above:

Foo default constructor!
if
Foo destructor!

But for gcc, (All four compiling options: -std=c++11, -std=c++14, -std=c++17 and -std=c++2a), the program generated different output:

Foo default constructor!
if
Foo move constructor!
Foo destructor!
Foo destructor!

So it means gcc generated both two variables: “Foo temp” and “auto f“. It not only means clang does better optimization than gcc in this scenario, but means if you do something in move constructor, and expect it should be called. You program logic will depend on the compiler: it works under gcc but not for clang. Beware of this trap, otherwise it may bite you one day, like me today!

A scenario in which clang will generate ud2 instruction while gcc not

Check following main.cpp:

# cat main.cpp
#include <functional>
#include <thread>

int main()
{
    int a = 2;

    std::function<void ()> work = [&]()
    {
        if (a < 1) {
            return 1;
        }
        while (1)
        {
            if (a > 1)
            {
                break;
            }
        }
    };


    std::thread t(mergeWork);
    t.join();
    return 0;
}

The prototype of work is void (), while in a < 1 branch, it actually has a return value:

if (a < 1) {
    return 1;
}

Compile the program with g++, and execute it:

# g++ -g -pthread main.cpp
# ./a.out
#

It runs smoothly. Switch to clang++:

# clang++ -g -pthread main.cpp
main.cpp:20:5: warning: control may reach end of non-void lambda [-Wreturn-type]
    };
    ^
1 warning generated.
# ./a.out
Illegal instruction (core dumped)

A warning is generated during building and “Illegal instruction” occurs during running. Check the assembly code of work:

 disassemble
Dump of assembler code for function main::$_0::operator()() const:
   0x0000555555555100 <+0>:     push   %rbp
   0x0000555555555101 <+1>:     mov    %rsp,%rbp
   0x0000555555555104 <+4>:     mov    %rdi,-0x8(%rbp)
   0x0000555555555108 <+8>:     mov    -0x8(%rbp),%rdi
=> 0x000055555555510c <+12>:    mov    (%rdi),%rax
   0x000055555555510f <+15>:    cmpl   $0x1,(%rax)
   0x0000555555555112 <+18>:    mov    %rdi,-0x10(%rbp)
   0x0000555555555116 <+22>:    jge    0x555555555123 <main::$_0::operator()() const+35>
   0x000055555555511c <+28>:    mov    $0x1,%eax
   0x0000555555555121 <+33>:    pop    %rbp
   0x0000555555555122 <+34>:    retq
   0x0000555555555123 <+35>:    jmpq   0x555555555128 <main::$_0::operator()() const+40>
   0x0000555555555128 <+40>:    mov    -0x10(%rbp),%rax
   0x000055555555512c <+44>:    mov    (%rax),%rcx
   0x000055555555512f <+47>:    cmpl   $0x1,(%rcx)
   0x0000555555555132 <+50>:    jle    0x55555555513d <main::$_0::operator()() const+61>
   0x0000555555555138 <+56>:    jmpq   0x555555555142 <main::$_0::operator()() const+66>
   0x000055555555513d <+61>:    jmpq   0x555555555128 <main::$_0::operator()() const+40>
   0x0000555555555142 <+66>:    ud2
End of assembler dump.

We can find an ud2 instruction at the end of lambda function. Modify the a < 1 branch:

if (a < 1) {
     return;
 }

This time, the program runs OK.

Clang seems to be generating more user-friendly error message than gcc

Check following simple C++ program:

#include <string>
#include <utility>

class A 
{
public:
    A (int a) {};
};

int main()
{

    std::pair<std::string, A> p;
    return 0;
}

Compile it with newest gcc 7.3.0, following errors are generated:

$ g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:13:31: error: no matching function for call to ‘std::pair<std::__cxx11::basic_string<char>, A>::pair()’
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:431:9: note: candidate: template<class ... _Args1, long unsigned int ..._Indexes1, class ... _Args2, long unsigned int ..._Indexes2> std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>)
         pair(tuple<_Args1...>&, tuple<_Args2...>&,
         ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:431:9: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 4 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:364:9: note: candidate: template<class ... _Args1, class ... _Args2> std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>)
         pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>);
         ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:364:9: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 3 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:359:21: note: candidate: template<class _U1, class _U2, typename std::enable_if<(std::_PCC<((! std::is_same<std::__cxx11::basic_string<char>, _U1>::value) || (! std::is_same<A, _U2>::value)), std::__cxx11::basic_string<char>, A>::_MoveConstructiblePair<_U1, _U2>() && (! std::_PCC<((! std::is_same<std::__cxx11::basic_string<char>, _U1>::value) || (! std::is_same<A, _U2>::value)), std::__cxx11::basic_string<char>, A>::_ImplicitlyMoveConvertiblePair<_U1, _U2>())), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(std::pair<_U1, _U2>&&)
  explicit constexpr pair(pair<_U1, _U2>&& __p)
                     ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:359:21: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 1 argument, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:349:12: note: candidate: template<class _U1, class _U2, typename std::enable_if<(std::_PCC<((! std::is_same<std::__cxx11::basic_string<char>, _U1>::value) || (! std::is_same<A, _U2>::value)), std::__cxx11::basic_string<char>, A>::_MoveConstructiblePair<_U1, _U2>() && std::_PCC<((! std::is_same<std::__cxx11::basic_string<char>, _U1>::value) || (! std::is_same<A, _U2>::value)), std::__cxx11::basic_string<char>, A>::_ImplicitlyMoveConvertiblePair<_U1, _U2>()), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(std::pair<_U1, _U2>&&)
  constexpr pair(pair<_U1, _U2>&& __p)
            ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:349:12: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 1 argument, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:339:21: note: candidate: template<class _U1, class _U2, typename std::enable_if<(_MoveConstructiblePair<_U1, _U2>() && (! _ImplicitlyMoveConvertiblePair<_U1, _U2>())), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(_U1&&, _U2&&)
  explicit constexpr pair(_U1&& __x, _U2&& __y)
                     ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:339:21: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 2 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:330:12: note: candidate: template<class _U1, class _U2, typename std::enable_if<(_MoveConstructiblePair<_U1, _U2>() && _ImplicitlyMoveConvertiblePair<_U1, _U2>()), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(_U1&&, _U2&&)
  constexpr pair(_U1&& __x, _U2&& __y)
            ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:330:12: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 2 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:321:17: note: candidate: template<class _U2, typename std::enable_if<_CopyMovePair<false, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, _U2>(), bool>::type <anonymous> > std::pair<_T1, _T2>::pair(const _T1&, _U2&&)
        explicit pair(const _T1& __x, _U2&& __y)
                 ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:321:17: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 2 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:314:18: note: candidate: template<class _U2, typename std::enable_if<_CopyMovePair<true, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, _U2>(), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(const _T1&, _U2&&)
        constexpr pair(const _T1& __x, _U2&& __y)
                  ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:314:18: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 2 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:307:27: note: candidate: template<class _U1, typename std::enable_if<_MoveCopyPair<false, _U1, A>(), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(_U1&&, const _T2&)
        explicit constexpr pair(_U1&& __x, const _T2& __y)
                           ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:307:27: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 2 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:300:18: note: candidate: template<class _U1, typename std::enable_if<_MoveCopyPair<true, _U1, A>(), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(_U1&&, const _T2&)
        constexpr pair(_U1&& __x, const _T2& __y)
                  ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:300:18: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 2 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:293:17: note: candidate: std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = std::__cxx11::basic_string<char>; _T2 = A]
       constexpr pair(pair&&) = default;
                 ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:293:17: note:   candidate expects 1 argument, 0 provided
/usr/include/c++/7.3.0/bits/stl_pair.h:292:17: note: candidate: std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = std::__cxx11::basic_string<char>; _T2 = A]
       constexpr pair(const pair&) = default;
                 ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:292:17: note:   candidate expects 1 argument, 0 provided
/usr/include/c++/7.3.0/bits/stl_pair.h:289:21: note: candidate: template<class _U1, class _U2, typename std::enable_if<(std::_PCC<((! std::is_same<std::__cxx11::basic_string<char>, _U1>::value) || (! std::is_same<A, _U2>::value)), std::__cxx11::basic_string<char>, A>::_ConstructiblePair<_U1, _U2>() && (! std::_PCC<((! std::is_same<std::__cxx11::basic_string<char>, _U1>::value) || (! std::is_same<A, _U2>::value)), std::__cxx11::basic_string<char>, A>::_ImplicitlyConvertiblePair<_U1, _U2>())), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&)
  explicit constexpr pair(const pair<_U1, _U2>& __p)
                     ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:289:21: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 1 argument, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:280:19: note: candidate: template<class _U1, class _U2, typename std::enable_if<(std::_PCC<((! std::is_same<std::__cxx11::basic_string<char>, _U1>::value) || (! std::is_same<A, _U2>::value)), std::__cxx11::basic_string<char>, A>::_ConstructiblePair<_U1, _U2>() && std::_PCC<((! std::is_same<std::__cxx11::basic_string<char>, _U1>::value) || (! std::is_same<A, _U2>::value)), std::__cxx11::basic_string<char>, A>::_ImplicitlyConvertiblePair<_U1, _U2>()), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&)
         constexpr pair(const pair<_U1, _U2>& __p)
                   ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:280:19: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 1 argument, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:258:26: note: candidate: template<class _U1, class _U2, typename std::enable_if<(_ConstructiblePair<_U1, _U2>() && (! _ImplicitlyConvertiblePair<_U1, _U2>())), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(const _T1&, const _T2&)
       explicit constexpr pair(const _T1& __a, const _T2& __b)
                          ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:258:26: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 2 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:249:17: note: candidate: template<class _U1, class _U2, typename std::enable_if<(_ConstructiblePair<_U1, _U2>() && _ImplicitlyConvertiblePair<_U1, _U2>()), bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair(const _T1&, const _T2&)
       constexpr pair(const _T1& __a, const _T2& __b)
                 ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:249:17: note:   template argument deduction/substitution failed:
test.cpp:13:31: note:   candidate expects 2 arguments, 0 provided
     std::pair<std::string, A> p;
                               ^
In file included from /usr/include/c++/7.3.0/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/7.3.0/bits/char_traits.h:39,
                 from /usr/include/c++/7.3.0/string:40,
                 from test.cpp:1:
/usr/include/c++/7.3.0/bits/stl_pair.h:231:26: note: candidate: template<class _U1, class _U2, typename std::enable_if<std::__and_<std::is_default_constructible<_Tp>, std::is_default_constructible<_U2>, std::__not_<std::__and_<std::__is_implicitly_default_constructible<_U1>, std::__is_implicitly_default_constructible<_U2> > > >::value, bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair()
       explicit constexpr pair()
                          ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:231:26: note:   template argument deduction/substitution failed:
/usr/include/c++/7.3.0/bits/stl_pair.h:230:59: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
                                    ::value, bool>::type = false>
                                                           ^~~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:230:59: note: invalid template non-type parameter
/usr/include/c++/7.3.0/bits/stl_pair.h:218:26: note: candidate: template<class _U1, class _U2, typename std::enable_if<std::__and_<std::__is_implicitly_default_constructible<_U1>, std::__is_implicitly_default_constructible<_U2> >::value, bool>::type <anonymous> > constexpr std::pair<_T1, _T2>::pair()
       _GLIBCXX_CONSTEXPR pair()
                          ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:218:26: note:   template argument deduction/substitution failed:
/usr/include/c++/7.3.0/bits/stl_pair.h:216:59: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
                                    ::value, bool>::type = true>
                                                           ^~~~
/usr/include/c++/7.3.0/bits/stl_pair.h:216:59: note: invalid template non-type parameter

Honestly, I’m totally lost in the error messages and can’t find the root cause easily. Whereas using clang 5.0.1 to build it:

$ clang++ test.cpp
In file included from test.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.3.0/../../../../include/c++/7.3.0/string:40:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/char_traits.h:39:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_algobase.h:64:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_pair.h:219:18: error: no matching
      constructor for initialization of 'A'
      : first(), second() { }
                 ^
test.cpp:13:31: note: in instantiation of member function 'std::pair<std::__cxx11::basic_string<char>, A>::pair'
      requested here
    std::pair<std::string, A> p;
                              ^
test.cpp:7:5: note: candidate constructor not viable: requires single argument 'a', but no arguments were provided
    A (int a) {};
    ^
test.cpp:4:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were
      provided
class A
      ^
1 error generated.

It is very clear and I can figure out what is the problem soon. Through this simple test, clang seems generating more user-friendly error message than gcc.

Clang may be a better option than gcc when requiring much memory

I used an old machine (the OS is Arch Linux, and memory less than 3G) to build stxxl project:

# cmake -DBUILD_TESTS=ON ..
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
......
# make VERBOSE=1
......
cd /root/stxxl/build/examples/applications && /usr/bin/c++  -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES -I/root/stxxl/include -I/root/stxxl/build/include  -W -Wall -pedantic -Wno-long-long -Wextra -ftemplate-depth=1024 -std=c++11 -fopenmp -g   -o CMakeFiles/skew3-lcp.dir/skew3-lcp.cpp.o -c /root/stxxl/examples/applications/skew3-lcp.cpp

The default compiler is gcc 7.3.0, and the building process was stuck at compiling skew3-lcp.cpp. The output of htop showed that nearly all memory is occupied:

1

Switch to clang:

# cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DBUILD_TESTS=ON ..
-- The C compiler identification is Clang 5.0.1
-- The CXX compiler identification is Clang 5.0.1
......
# make
......
[100%] Linking CXX executable test1
[100%] Built target test1

The project can be built successfully, and the peak memory used for compiling skew3-lcp.cpp is 1.78G. Based on this test, if you have compiling task which needs much memory, clang may be a better choice than gcc.