Bug 2116376 - "static constexpr" does not be evaluated at compiling time with "-std=c++14" on aarch64.
Summary: "static constexpr" does not be evaluated at compiling time with "-std=c++14" ...
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 9
Classification: Red Hat
Component: gcc
Version: 9.0
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: rc
: ---
Assignee: Marek Polacek
QA Contact: qe-baseos-tools-bugs
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2022-08-08 12:32 UTC by Kirby Zhou
Modified: 2023-07-18 14:25 UTC (History)
5 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2022-08-12 16:48:06 UTC
Type: Bug
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Issue Tracker RHELPLAN-130485 0 None None None 2022-08-08 12:44:27 UTC

Description Kirby Zhou 2022-08-08 12:32:15 UTC
Description of problem:

"static constexpr" does not be evaluated at compiling time with "-std=c++14" on aarch64.


Version-Release number of selected component (if applicable):

gcc-c++-11.2.1-9.4.el9.aarch64
gcc-c++-11.3.1-2.1.el9.aarch64

How reproducible:

100%

Steps to Reproduce:
1. edit errdemo.cc
////////////
#include <functional>
#include <cstdlib>

template<typename SSL_TYPE>
struct TypeTraits {};

template<> struct TypeTraits<void> {
  static constexpr auto kFreeFunc = &free;
};

int main()
{
        std::function<void(void*)> x = TypeTraits<void>::kFreeFunc;
}
////////////


2. compile it with -std=c++14 -lcrypt
#] g++ -std=c++14 errdemo.cc 

Actual results:

/bin/ld: /tmp/ccBvnuK4.o: in function `main':
errdemo.cc:(.text+0xc): undefined reference to `TypeTraits<void>::kFreeFunc'
/bin/ld: errdemo.cc:(.text+0x10): undefined reference to `TypeTraits<void>::kFreeFunc'
collect2: error: ld returned 1 exit status


Expected results:

Just compile success

Additional info:

I have tested many case:

It happens only with gcc11 -std=c++14 or gcc11 -std=c++11.

All the following case is OK:
gcc11 -std=c++17
gcc11 -std=c++14 -O2
gcc11 -std=c++11 -O2
gcc10 -std=c++17
gcc10 -std=c++14
gcc10 -std=c++11
gcc8 -std=c++17
gcc8 -std=c++14
gcc8 -std=c++11
gcc4.8 -std=c++11

Comment 1 Florian Weimer 2022-08-08 13:25:14 UTC
Adding this

decltype(SslTypeTraits<X509>::kFreeFunc) SslTypeTraits<X509>::kFreeFunc;

appears to fix it. I suspect the std::function constructor causes kFreeFunc to be ODR-used. In that case, it's a source code bug.

Comment 2 Kirby Zhou 2022-08-09 04:33:59 UTC
You mean this may be a bug of libstdc++ instead of gcc compiler itself?

BTW, it wont happens with "-O2" or on x86_64.

Comment 3 Kirby Zhou 2022-08-09 04:39:16 UTC
And your method is very hard to be used in template header files

Comment 4 Florian Weimer 2022-08-09 07:30:38 UTC
(In reply to Kirby Zhou from comment #2)
> You mean this may be a bug of libstdc++ instead of gcc compiler itself?

I mean a bug in your source code. The issue is that in your updated reproducer, the argument type of the std::function constructor is deduced as

  void (* const&)(void*) noexcept

and the const reference makes kFreeFunc ODR-used, requiring the separate, out-of-line definition of kFreeFunc.

> BTW, it wont happens with "-O2" or on x86_64.

C++ does not require diagnostics for these issues.

(In reply to Kirby Zhou from comment #3)
> And your method is very hard to be used in template header files

With the updated source code, you could try this:

        std::function<void(void*)> x = +TypeTraits<void>::kFreeFunc;

This causes the std::function constructor to bind to a temporary.

Comment 5 Kirby Zhou 2022-08-09 12:21:16 UTC
However, why -std=c++17 can pass with and without "+TypeTraits"?
Both c++14 and c++17, the constructors are same:

    std::function<void (void*)>::function<void (* const&)(void*) noexcept, void>(void (* const&)(void*) noexcept)


And under RHEL8, gcc-8 can also pass with and without "+TypeTraits", with -std=c++11 or -std=c++14
And under RHEL7, gcc-4.8 "-std=c++11" can pass without "+TypeTraits", but can not pass with "+TypeTraits".






[kirbyzhou@el7dev_kirbyzhou constexpr]$ g++ -std=c++11 errdemo.cc 
/tmp/ccuoTuqM.o: In function `main':
errdemo.cc:(.text+0x8): undefined reference to `TypeTraits<void>::kFreeFunc'
errdemo.cc:(.text+0xc): undefined reference to `TypeTraits<void>::kFreeFunc'
collect2: error: ld returned 1 exit status
[kirbyzhou@el7dev_kirbyzhou constexpr]$ cat errdemo.cc 
#include <functional>
#include <cstdlib>

template<typename SSL_TYPE>
struct TypeTraits {};

template<> struct TypeTraits<void> {
  static constexpr auto kFreeFunc = &free;
};

int main()
{
	std::function<void(void*)> x = +TypeTraits<void>::kFreeFunc;
}

Comment 6 Marek Polacek 2022-08-09 19:00:53 UTC
In C++17, static constexpr data members are implicitly inline (which makes them definitions).
So with -std=c++17 the code works because in C++17, TypeTraits<void>::kFreeFunc is a definition,
but in C++14 it's only a declaration, and as Florian said, since TypeTraits<void>::kFreeFunc is
ODR-used, a definition is needed.

See
https://developers.redhat.com/articles/2021/08/06/porting-your-code-c17-gcc-11#static_constexpr_and_consteval_class_members_implicitly_inline

In C++14, you could make TypeTraits<void>::kFreeFunc a definition like this (unfortunately
without using 'auto'):

#include <functional>
#include <cstdlib>

template<typename SSL_TYPE>
struct TypeTraits {};

template<> struct TypeTraits<void> {
  static constexpr void (*kFreeFunc) (void *) = &free;
};

constexpr void (*TypeTraits<void>::kFreeFunc) (void *);

int main()
{
        std::function<void(void*)> x = TypeTraits<void>::kFreeFunc;
}

Not a bug.

Comment 7 Kirby Zhou 2022-08-11 01:08:04 UTC
I get your point.

But:
  Under RHEL8, gcc-8 can also pass with and without "+TypeTraits", with -std=c++11 or -std=c++14
  Under RHEL7, gcc-4.8 "-std=c++11" can pass without "+TypeTraits", but can not pass with "+TypeTraits".


So the behavior of "gcc-8 -std=c++14" "gcc-8 -std=c++11" ""gcc-4.8 -std=c++11" is wrong ?
Or it is just undefined behavior?

Comment 8 Kirby Zhou 2022-08-12 16:10:36 UTC
For correction, It happens on gcc11 on x86_64 too.

I have tested many case:

It happens only with gcc11 -std=c++14 or gcc11 -std=c++11.

All the following case are OK:

gcc11 -std=c++17
gcc11 -std=c++14 -O2
gcc11 -std=c++11 -O2
gcc10 -std=c++17
gcc10 -std=c++14
gcc10 -std=c++11
gcc8 -std=c++17
gcc8 -std=c++14
gcc8 -std=c++11
gcc4.8 -std=c++11

Please reconsider whether this situation is reasonable.

Comment 10 Jakub Jelinek 2022-08-12 16:22:55 UTC
There is nothing to reconsider, that is simply how C++11/14 vs. C++17/20 works.
When TypeTraits<void>::kFreeFunc is ODR-used, it needs to be defined, not just declared.
If you don't do that, your program isn't valid C++.
It might still compile and link, but might not.


Note You need to log in before you can comment on or make changes to this bug.