Why I love compilers

Tags: programming, musings

Published on
« Previous post: Searching for swear words in the Enron … — Next post: Some leaky abstractions in C++11 »

Compilers are getting better and better at interpreting the stupid stuff I throw at them. Every once in a while, I manage to surprise them and myself by my stupidity. This time, for your pleasure, a minimum working example—or rather a minimum non-working example:

namespace
{
#include <list>
}

int main(int, char**)
{
  std::list<int> l = {1,2,3,4};
  return 0;
}

Here is what clang++ has to say about this:

$ clang++ --version
clang version 3.6.2 (tags/RELEASE_362/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
$ clang++ -std=c++11 uh-oh.cc
In file included from uh-oh.cc:3:
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/list:61:
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/allocator.h:46:
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/x86_64-unknown-linux-gnu/bits/c++allocator.h:33:
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/ext/new_allocator.h:33:
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:111:7: error: 
      'operator new' cannot be declared inside a namespace
void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc)
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:113:7: error: 
      'operator new[]' cannot be declared inside a namespace
void* operator new[](std::size_t) _GLIBCXX_THROW (std::bad_alloc)
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:115:6: error: 
      'operator delete' cannot be declared inside a namespace
void operator delete(void*) _GLIBCXX_USE_NOEXCEPT
     ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:117:6: error: 
      'operator delete[]' cannot be declared inside a namespace
void operator delete[](void*) _GLIBCXX_USE_NOEXCEPT
     ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:119:7: error: 
      'operator new' cannot be declared inside a namespace
void* operator new(std::size_t, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:121:7: error: 
      'operator new[]' cannot be declared inside a namespace
void* operator new[](std::size_t, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:123:6: error: 
      'operator delete' cannot be declared inside a namespace
void operator delete(void*, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
     ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:125:6: error: 
      'operator delete[]' cannot be declared inside a namespace
void operator delete[](void*, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
     ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:129:14: error: 
      'operator new' cannot be declared inside a namespace
inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
             ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:131:14: error: 
      'operator new[]' cannot be declared inside a namespace
inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
             ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:135:13: error: 
      'operator delete' cannot be declared inside a namespace
inline void operator delete  (void*, void*) _GLIBCXX_USE_NOEXCEPT { }
            ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/new:136:13: error: 
      'operator delete[]' cannot be declared inside a namespace
inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { }
            ^
uh-oh.cc:8:18: error: no matching constructor for initialization of
      'std::list<int>'
  std::list<int> l = {1,2,3,4};
                 ^   ~~~~~~~~~
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/stl_list.h:697:9: note: 
      candidate constructor template not viable: requires at most 3 arguments, but
      4 were provided
        list(_InputIterator __first, _InputIterator __last,
        ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/stl_list.h:628:7: note: 
      candidate constructor not viable: requires at most 3 arguments, but 4 were
      provided
      list(size_type __n, const value_type& __value,
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/stl_list.h:678:7: note: 
      candidate constructor not viable: requires at most 2 arguments, but 4 were
      provided
      list(initializer_list<value_type> __l,
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/stl_list.h:604:7: note: 
      candidate constructor not viable: requires single argument '__a', but 4
      arguments were provided
      list(const allocator_type& __a) _GLIBCXX_NOEXCEPT
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/stl_list.h:616:7: note: 
      candidate constructor not viable: requires single argument '__n', but 4
      arguments were provided
      list(size_type __n)
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/stl_list.h:655:7: note: 
      candidate constructor not viable: requires single argument '__x', but 4
      arguments were provided
      list(const list& __x)
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/stl_list.h:667:7: note: 
      candidate constructor not viable: requires single argument '__x', but 4
      arguments were provided
      list(list&& __x) noexcept
      ^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/stl_list.h:593:7: note: 
      candidate constructor not viable: requires 0 arguments, but 4 were provided
      list()
      ^
13 errors generated.

Suddenly, everything appears to be broken. No initializer lists even though C++11 is supported? What the what? Let us check what g++ has to add:

$ g++ --version
g++ (GCC) 5.2.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ -std=c++11 uh-oh.cc
In file included from /usr/include/c++/5.2.0/ext/new_allocator.h:33:0,
                 from /usr/include/c++/5.2.0/x86_64-unknown-linux-gnu/bits/c++allocator.h:33,
                 from /usr/include/c++/5.2.0/bits/allocator.h:46,
                 from /usr/include/c++/5.2.0/list:61,
                 from uh-oh.cc:3:
/usr/include/c++/5.2.0/new:112:41: error: ‘void* {anonymous}::operator new({anonymous}::std::size_t)’ may not be declared within a namespace
   __attribute__((__externally_visible__));
                                         ^
/usr/include/c++/5.2.0/new:114:41: error: ‘void* {anonymous}::operator new []({anonymous}::std::size_t)’ may not be declared within a namespace
   __attribute__((__externally_visible__));
                                         ^
/usr/include/c++/5.2.0/new:116:41: error: ‘void {anonymous}::operator delete(void* ’ may not be declared within a namespace
   __attribute__((__externally_visible__));
                                         ^
/usr/include/c++/5.2.0/new:118:41: error: ‘void {anonymous}::operator delete [](void*)’ may not be declared within a namespace
   __attribute__((__externally_visible__));
                                         ^
/usr/include/c++/5.2.0/new:120:41: error: ‘void* {anonymous}::operator new({anonymous}::std::size_t, const {anonymous}::std::nothrow_t&)’ may not be declared within a namespace
   __attribute__((__externally_visible__));
                                         ^
/usr/include/c++/5.2.0/new:122:41: error: ‘void* {anonymous}::operator new []({anonymous}::std::size_t, const {anonymous}::std::nothrow_t&)’ may not be declared within a namespace
   __attribute__((__externally_visible__));
                                         ^
/usr/include/c++/5.2.0/new:124:41: error: ‘void {anonymous}::operator delete(void*, const {anonymous}::std::nothrow_t&)’ may not be declared within a namespace
   __attribute__((__externally_visible__));
                                         ^
/usr/include/c++/5.2.0/new:126:41: error: ‘void {anonymous}::operator delete [](void*, const {anonymous}::std::nothrow_t&)’ may not be declared within a namespace
   __attribute__((__externally_visible__));
                                         ^
In file included from /usr/include/c++/5.2.0/bits/stl_algobase.h:59:0,
                 from /usr/include/c++/5.2.0/list:60,
                 from uh-oh.cc:3:
/usr/include/c++/5.2.0/new:129:51: error: ‘void* {anonymous}::operator new({anonymous}::std::size_t, void*)’ may not be declared within a namespace
 inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
                                                   ^
/usr/include/c++/5.2.0/new:131:53: error: ‘void* {anonymous}::operator new []({anonymous}::std::size_t, void*)’ may not be declared within a namespace
 inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
                                                     ^
/usr/include/c++/5.2.0/new:135:45: error: ‘void {anonymous}::operator delete(void*, void*)’ may not be declared within a namespace
 inline void operator delete  (void*, void*) _GLIBCXX_USE_NOEXCEPT { }
                                             ^
/usr/include/c++/5.2.0/new:136:45: error: ‘void {anonymous}::operator delete [](void*, void*)’ may not be declared within a namespace
 inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { }
                                             ^
uh-oh.cc: In function ‘int main(int, char**)’:
uh-oh.cc:8:3: error: reference to ‘std’ is ambiguous
   std::list<int> l = {1,2,3,4};
   ^
<built-in>: note: candidates are: namespace std { }
In file included from /usr/include/c++/5.2.0/bits/stl_algobase.h:59:0,
                 from /usr/include/c++/5.2.0/list:60,
                 from uh-oh.cc:3:
/usr/include/c++/5.2.0/x86_64-unknown-linux-gnu/bits/c++config.h:195:1: note:                 namespace <unnamed>::std { }
 {
 ^
uh-oh.cc:8:13: error: expected primary-expression before ‘int’
   std::list<int> l = {1,2,3,4};
         ^

Interesting. It seems to detect that including a named namespace in an unnamed namespace was not the best idea. Of course, this is not what I originally intended when I encountered this error for the first time—I was rather stupidly including something that in turn included an STL header.

It is somewhat amazing to me that the simple addition of an anonymous namespace results in such an amount of error messages. The folks at StackExchange even had a contest for this sort of thing. Against their submissions, this problem very much pales in comparison.

Happy programming—be smarter than me.