Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.
RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.

Bug 2116376

Summary: "static constexpr" does not be evaluated at compiling time with "-std=c++14" on aarch64.
Product: Red Hat Enterprise Linux 9 Reporter: Kirby Zhou <kirbyzhou>
Component: gccAssignee: Marek Polacek <mpolacek>
gcc sub component: system-version QA Contact: qe-baseos-tools-bugs
Status: CLOSED NOTABUG Docs Contact:
Severity: unspecified    
Priority: unspecified CC: ahajkova, fweimer, jakub, ohudlick, sipoyare
Version: 9.0Keywords: Reopened
Target Milestone: rcFlags: pm-rhel: mirror+
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2022-08-12 16:48:06 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

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.