Bug 95175 - [9/10/11 Regression] constexpr and alias template
Summary: [9/10/11 Regression] constexpr and alias template
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.3.0
: P2 normal
Target Milestone: 9.4
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2020-05-17 15:57 UTC by Нина Диденко
Modified: 2020-06-03 19:39 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-05-18 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Нина Диденко 2020-05-17 15:57:46 UTC
This snippet successfully compiles using gcc6 up to gcc8.
When building using gcc 9.3.0 there is an error

template<typename R, typename... Types>
using Function = R(*)(Types...);

struct Struct
{
  void *addr;

  template<typename R, typename... Types>
  constexpr Struct(Function<R, Types...> addr) : addr((void*)(addr)) {}
};

void TestFunction()
{
}

int main(void)
{
  static constexpr Struct functions[]{
    {TestFunction},
  };
}

The error is

4.cpp: In function 'int main()':
4.cpp:20:3: error: 'constexpr Struct::Struct(Function<R, Types ...>) [with R = void; Types = {}; Function<R, Types ...> = void (*)()]' called in a constant expression
   20 |   };
      |   ^
4.cpp:9:13: note: 'constexpr Struct::Struct(Function<R, Types ...>) [with R = void; Types = {}; Function<R, Types ...> = void (*)()]' is not usable as a 'constexpr' function because:
    9 |   constexpr Struct(Function<R, Types...> addr) : addr((void*)(addr)) {}

The full product code

https://github.com/TES3MP/openmw-tes3mp/blob/0.7.1/apps/openmw-mp/Script/ScriptFunctions.hpp#L120
https://github.com/TES3MP/openmw-tes3mp/blob/0.7.1/apps/openmw-mp/Script/Types.hpp#L99
Comment 1 Marek Polacek 2020-05-18 23:45:02 UTC
Confirmed, we used to accept this.

Started with r9-6136-g43574e4ff2afd4a2e47c179921a9b5661786ebf3
Comment 2 Jason Merrill 2020-05-27 18:14:51 UTC
Interesting, the standard doesn't actually seem to specify anything about casting a function pointer to pointer to void, which is explicitly not an object pointer under http://eel.is/c++draft/basic.compound#3:

[ Note: A pointer to void does not have a pointer-to-object type, however, because void is not an object type. — end note ]

The only thing it says about casting between function and non-function pointers is http://eel.is/c++draft/expr.reinterpret.cast#8:
Converting a function pointer to an object pointer type or vice versa is conditionally-supported.

We currently treat the C-style cast as a reinterpret_cast, and therefore reject it in a constant expression; GCC 9 is better about rejecting reinterpret_cast than earlier versions that wrongly allowed them.

Curiously, clang rejects a static_cast from function pointer to void*, allows a reinterpret_cast, rejects the reinterpret_cast in a constant expression, but allows a C-style cast in a constant expression.  That seems inconsistent.

Suspending pending feedback from the C++ committee.
Comment 3 Jason Merrill 2020-06-03 19:39:31 UTC
(In reply to Jason Merrill from comment #2)
> Interesting, the standard doesn't actually seem to specify anything about
> casting a function pointer to pointer to void, which is explicitly not an
> object pointer under http://eel.is/c++draft/basic.compound#3:
> 
> [ Note: A pointer to void does not have a pointer-to-object type, however,
> because void is not an object type. — end note ]

I was misreading this passage; pointer to void is an object pointer type even though it is not a pointer-to-object type.

"The type of a pointer to cv void or a pointer to an object type is called an object pointer type."
 
> The only thing it says about casting between function and non-function
> pointers is http://eel.is/c++draft/expr.reinterpret.cast#8:
> Converting a function pointer to an object pointer type or vice versa is
> conditionally-supported.

So this passage covers this case.

> We currently treat the C-style cast as a reinterpret_cast, and therefore
> reject it in a constant expression; GCC 9 is better about rejecting
> reinterpret_cast than earlier versions that wrongly allowed them.

And this is correct.

> Curiously, clang rejects a static_cast from function pointer to void*,
> allows a reinterpret_cast, rejects the reinterpret_cast in a constant
> expression, but allows a C-style cast in a constant expression.  That seems
> inconsistent.

Richard Smith from the clang team agrees that this is a clang bug.

So, your testcase is ill-formed.