Bug 78022 - constexpr int template rejected unless constructor is used before hand
Summary: constexpr int template rejected unless constructor is used before hand
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 5.4.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2016-10-18 15:16 UTC by fiesh
Modified: 2018-12-06 18:43 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 5.3.0, 5.4.0, 6.4.0, 7.0, 7.3.0, 8.0
Last reconfirmed: 2018-02-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description fiesh 2016-10-18 15:16:44 UTC
The following piece of code does not compile.  Since clang 3.8.1 compiles it, and furthermore changes that would appear inconsequential make it compile, I suspect it might be an issue of GCC:

------------------
#include <array>

template<typename T>
struct A
{
	template<typename... Args>
		constexpr A(Args&&... args) :
			entries_{std::forward<Args>(args)...} {}
	std::array<T, 1> entries_;
};

struct B : public A<int>
{
	using A<int>::A;
};

// Uncommenting the following line makes this file compile.
//constexpr B p{0};
// Commenting the following line makes this file compile.
template<typename>
struct X
{
	X()
	{
		// The following line is fine.
		const B b0{0};
		// The following line produces an error.
		constexpr B b1{0};
	}
};
------------------

The output is as follows:
% g++ -std=c++11 -c test.cpp
test.cpp: In constructor ‘X<T>::X()’:
test.cpp:31:20: error: ‘constexpr B::B(Args&& ...) [with Args = {int}]’ used before its definition
    constexpr B b1{0};
Comment 1 fiesh 2016-10-18 15:28:38 UTC
The same happens with 6.2.1.
Comment 2 Andrew Pinski 2016-10-19 00:17:26 UTC
Confirmed.
struct X can be a function too.
Comment 3 fiesh 2018-01-30 12:26:55 UTC
Interestingly, clang-5 no longer compiles this code:

<source>:28:15: error: constexpr variable 'b1' must be initialized by a constant expression
                constexpr B b1{0};
                            ^~~~~
<source>:28:15: note: constructor inherited from base class 'A<int>' cannot be used in a constant expression; derived class cannot be implicitly initialized
<source>:14:16: note: declared here
        using A<int>::A;
                      ^
1 error generated.
Compiler returned: 1

So gcc, clang <=4 and clang-5 behave pairwise differently.  At most one of them can be right, who might it be?
Comment 4 Jonathan Wakely 2018-02-12 14:21:52 UTC
Still fails on trunk (and Clang-5+ as reported). Clang-4 and EDG 4.14 accept it.

Slightly reduced:

template<typename T>
struct A
{
	template<typename... Args>
		constexpr A(Args&&...){}
};

struct B : public A<int>
{
	using A<int>::A;
};

// Uncommenting the following line makes this file compile.
//constexpr B p{0};
// Commenting the following line makes this file compile.
template<typename>
struct X
{
	X()
	{
		// The following line is fine.
		const B b0{0};
		// The following line produces an error.
		constexpr B b1{0};
	}
};
Comment 5 fiesh 2018-12-06 12:57:39 UTC
The code still does not compile with gcc-8.2 but does compile on trunk now!

Conversely, clang consistently refuses to compile it since clang-5.

So I guess this can be closed, unless clang is actually correct and my bug report was flawed because the code is actually invalid?

For what it's worth, godbolt shows that both MSVC and ICC accept the code as valid.
Comment 6 Marek Polacek 2018-12-06 18:39:55 UTC
That was fixed by r261084.
Comment 7 Marek Polacek 2018-12-06 18:43:41 UTC
Or, let's say, started to be accepted.