Bug 54483 - undefined reference to static constexpr in .so
Summary: undefined reference to static constexpr in .so
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 113465 (view as bug list)
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2012-09-04 18:30 UTC by Yogish Baliga
Modified: 2024-01-18 08:21 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-09-05 00:00:00


Attachments
Files for testcase of initial post (351 bytes, application/x-tar)
2014-11-30 15:17 UTC, Juisoo
Details
second test case (354 bytes, application/x-tar)
2014-11-30 15:33 UTC, Juisoo
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Yogish Baliga 2012-09-04 18:30:43 UTC
In a.hh 
---------

class A {
  static constexpr float val = 0.08;

  public:
   bool foo(const float v);
};


In a.cc
--------

bool A::foo(const float v) {
  return (v < -val);
}

Created a libfoo.so from the above code and linked this .so with another executable using A::foo(const float) method.

Creating an executable result in "undefined reference to A::val"

If I replace val with -0.08 and change foo method with return (v < val), val is getting inlined.
Comment 1 Jakub Jelinek 2012-09-05 07:49:57 UTC
This is invalid as per [class.static.data]/3 :
"A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer."
Comment 2 Richard Biener 2012-09-05 09:21:42 UTC
.
Comment 3 Daniel Krügler 2012-09-05 11:12:13 UTC
(In reply to comment #1)
> This is invalid as per [class.static.data]/3 :

On C++11 level it should be valid, because odr-usage does not happen here according to [basic.def.odr] p3:

"A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless x is an object that satisfies the requirements for appearing in a constant expression (5.19) and ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied
to e, or e is a discarded-value expression (Clause 5)."
Comment 4 Paolo Carlini 2012-09-05 11:21:06 UTC
Let's reopen this, then.
Comment 5 Jonathan Wakely 2012-09-07 08:30:36 UTC
(In reply to comment #3)
> (In reply to comment #1)
> > This is invalid as per [class.static.data]/3 :
> 
> On C++11 level it should be valid

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#712 is post-C++11 but as a DR we should implement it for all values of -std
Comment 6 Juisoo 2014-11-30 15:17:46 UTC
Created attachment 34147 [details]
Files for testcase of initial post
Comment 7 Juisoo 2014-11-30 15:33:39 UTC
Created attachment 34148 [details]
second test case
Comment 8 Juisoo 2014-11-30 15:34:30 UTC
The described case seems to work in GCC 4.9.2  with the attached files and
g++ -c -fpic testicle.cc -std=c++11
g++ -shared -o libtesticle.so testicle.o 
g++ -L/home/usack/entwicklung/tetris -Wall -o testicles main.cc -ltesticle -std=c++11

However, if I add another data member which is initialized with val by default, I still get the "undefined reference" error, see second attachment.
Comment 9 Mitsuru Kariya 2015-03-26 05:58:48 UTC
(In reply to Juisoo from comment #8)
> However, if I add another data member which is initialized with val by
> default, I still get the "undefined reference" error, see second attachment.

The second testcase is reduced like below.

============== testcase ==============
struct A {
    static constexpr float val = 0.08;
    A(const float& = val) {}
};

int main()
{
    A{};
}
============== testcase ==============
cf. http://melpon.org/wandbox/permlink/ZCbNwLlPQakWjluY


I think that the testcase is ill-formed because the A::val is odr-used.

When A's ctor is called with no argument,
  1) The lvalue-to-rvalue conversion is not applied to A::val.
     (Since the ctor's parameter is a reference type.)
  2) A::val is not a discarded-value expression.


On the other hand, A::val is not odr-used in the first testcase.
(Since the builtin unary - operator requires that its operand is a prvalue.)


So, I think that this pr is fixed.
(But I don't know whether this pr can be closed since I cannot find a test.)
Comment 10 Denis Sherstennikov 2016-02-10 17:24:17 UTC
Still an issue at gcc 5.3.0.
Comment 11 Andrew Pinski 2021-08-27 23:34:29 UTC
(In reply to Mitsuru Kariya from comment #9)
> (In reply to Juisoo from comment #8)
> > However, if I add another data member which is initialized with val by
> > default, I still get the "undefined reference" error, see second attachment.
> 
> The second testcase is reduced like below.
> 
> ============== testcase ==============
> struct A {
>     static constexpr float val = 0.08;
>     A(const float& = val) {}
> };
> 
> int main()
> {
>     A{};
> }
> ============== testcase ==============
> cf. http://melpon.org/wandbox/permlink/ZCbNwLlPQakWjluY

You still need:
constexpr float A::val;
Comment 12 Andrew Pinski 2024-01-18 04:17:14 UTC
*** Bug 113465 has been marked as a duplicate of this bug. ***
Comment 13 Thiago Macieira 2024-01-18 05:44:32 UTC
(In reply to Andrew Pinski from comment #11)
> You still need:
> constexpr float A::val;

In C++11 mode, yes.

C++17 made all static constexpr data members implicitly inline, which change the situation. Inline variables ought to be emitted on use and merged at runtime.

This explanation does not change the resolution of this bug report. But if you can update your code to use -std=c++17, gnu++17 or later, then the problem goes away.