Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gcc and clang disagree over constexpr function

Writting a simple compile time std::array factory from a generator function, I stumbled upon this: clang++ 3.5.1 and g++ 4.9.2 disagree on whether a function is constexpr or not.

The code (this is c++14!):

#include <array>
#include <utility>

    template <class T, std::size_t N, class GenType, std::size_t... I> 
    constexpr std::array<T, N>
make_array_impl (GenType gen, std::index_sequence <I...>) 
{
    return {{ gen (I)... }};
}

    template <class T, std::size_t N, class GenType> 
    constexpr std::array<T, N>
make_array (GenType gen)
{
    return make_array_impl <T, N> (
            gen, 
            std::make_index_sequence <N> {}
    );
}

    constexpr int
generator_const (std::size_t /* index */)
{
    return 1;
}

    constexpr auto
a = make_array <int, 3> (generator_const);

static_assert (a.size () == 3, "");
static_assert (a[0] == 1, "");
static_assert (a[1] == 1, "");
static_assert (a[2] == 1, "");

int main () {}

Compiling with g++:

migou ~ % g++ -std=c++14 ex.cpp  
ex.cpp:28:41:   in constexpr expansion of ‘make_array<int, 3ul, int (*)(long unsigned int)>(generator_const)’
ex.cpp:18:5:   in constexpr expansion of ‘make_array_impl<int, 3ul, int (*)(long unsigned int), {0ul, 1ul, 2ul}>(gen, (std::make_index_sequence<3ul>{}, std::make_index_sequence<3ul>()))’
ex.cpp:8:21: error: expression ‘generator_const’ does not designate a constexpr function
 return {{ gen (I)... }};

With clang++ it compiles just fine. Can I go on and consider this valid g++14 (and thus g++ bugged)?

like image 796
minusplus Avatar asked Feb 10 '15 16:02

minusplus


People also ask

What is the difference between Clang vs GCC vs LLVM?

With some benchmarks, it is seen that lld is faster than ld and even the newer ld-gold. Build tool – Perhaps another place where Clang Vs GCC difference comes to the forefront. GCC uses autotools and Make as its build tools whereas Clang/LLVM uses CMake as its build tool.

How many lines of code in GCC?

Code complexity – GCC is a very complicated software with more than 15 million lines of code. Although it has well-defined frontend/backend stages, the software in itself is more monolithic in nature. Let us now see how Clang Vs GCC would look.

What is the power of Clang/LLVM?

Clang/LLVM is a compiler toolchain that supports C, C++, and Objective-C natively. This sentence does not justify the power of Clang/LLVM. To understand why I rave about this compiler toolchain, I need to describe a bit more about how the modern compiler architecture looks like: Clang/LLVM is a textbook case of such an architecture.

What programming languages does clang support?

As can be seen from the name Clang supports mostly C, C++, and Objective-C. But the framework underlying Clang called LLVM is extensible enough to support newer languages like Julia and Swift. From the perspective of C++, both are excellent compilers supporting the C++17 standard.


2 Answers

As @Casey correctly pointed out in the comments, there is nothing foggy about the constexpr-ness of the implicit constructor of std::array or other aggregates:

12.1 Constructors [class.ctor]

5 A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration. The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no ctor-initializer (12.6.2) and an empty compound-statement. If that user-written default constructor would be ill-formed, the program is ill-formed. If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5), the implicitly-defined default constructor is constexpr. Before the defaulted default constructor for a class is implicitly defined, all the non-user-provided default constructors for its base classes and its nonstatic data members shall have been implicitly defined. [ Note: An implicitly-declared default constructor has an exception-specification (15.4). An explicitly-defaulted definition might have an implicit exceptionspecification, see 8.4. —end note ]

This has been fixed in the latest gcc HEAD 5.0.0 20150217, see this live example, and has been working in Clang since almost a year and a half now (since the 3.4 release IIRC, see this Q&A).

like image 148
TemplateRex Avatar answered Nov 06 '22 13:11

TemplateRex


This is kinda foggy. The rules for constexpr in C++14 forbid (N3797, 5.19/2 bullet 2)

an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor

constexpr is not part of the type, so the function pointer passed to make_array_impl is not a constexpr function. On the other hand, it refers to a constexpr function, and since this is constexpr evaluation, the compiler has to know that.

However, Clang supports that code, and GCC 4.9 doesn't claim conformance with relaxed constexpr functions, so I would trust Clang in this case.

like image 29
Sebastian Redl Avatar answered Nov 06 '22 14:11

Sebastian Redl