Bug 65579 - [C++11] gcc requires definition of a static constexpr member even though it is not odr-used
Summary: [C++11] gcc requires definition of a static constexpr member even though it i...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 5.0
: P3 normal
Target Milestone: 8.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2015-03-26 08:50 UTC by Mitsuru Kariya
Modified: 2017-11-06 17:47 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 4.9.3, 5.3.0, 6.0
Last reconfirmed: 2015-03-27 00:00:00


Attachments
g++ -v (1.17 KB, text/plain)
2015-03-26 08:50 UTC, Mitsuru Kariya
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mitsuru Kariya 2015-03-26 08:50:32 UTC
Created attachment 35143 [details]
g++ -v

The sample code below should be compiled and linked successfully but it causes a linkage error.

============== sample code ==============
template <typename>
struct S {
    int i;
};

struct T {
    static constexpr S<int> s{1};
};

int main()
{
    return T::s.i;
}
============== sample code ==============
cf. http://melpon.org/wandbox/permlink/JFgGdscpiHVEJpdb


I think that the T::s is not odr-used.


Note that it is compiled and linked successfully if S is not a template.

============== sample code ==============
struct S {
    int i;
};

struct T {
    static constexpr S s{1};
};

int main()
{
    return T::s.i;
}
============== sample code ==============
cf. http://melpon.org/wandbox/permlink/bvH2k7pW8WQSXQmN
Comment 1 Martin Sebor 2016-03-09 18:38:51 UTC
Re-confirmed with today's top of trunk (6.0) and all prior supported versions that implement constexpr.  See below.

The difference between the template and non-template case is the readonly bit that's set on the 's' field when S is an ordinary struct.  The bit is clear when S is a template.  The bit gets set in the c_apply_type_quals_to_decl() function in c-family/c-common.c called from  the cp_apply_type_quals_to_decl() function defined in cp/typeck.c.  The latter function executes the following condition just before calling c_apply_type_quals_to_decl().  COMPLETE_TYPE_P (type) is false when S is a (specialization of a template), causing the TYPE_QUAL_CONST to clear.

  /* Avoid setting TREE_READONLY incorrectly.  */
  /* We used to check TYPE_NEEDS_CONSTRUCTING here, but now a constexpr
     constructor can produce constant init, so rely on cp_finish_decl to
     clear TREE_READONLY if the variable has non-constant init.  */

  /* If the type has (or might have) a mutable component, that component
     might be modified.  */
  if (TYPE_HAS_MUTABLE_P (type) || !COMPLETE_TYPE_P (type))
    type_quals &= ~TYPE_QUAL_CONST;

  c_apply_type_quals_to_decl (type_quals, decl);

When S is made complete by this point (e.g., by causing S<int> to be instantiated, say by declaring an object of the type), the bit stays set and the test program links. 

The c_apply_type_quals_to_decl() function the does the following:

  if ((type_quals & TYPE_QUAL_CONST)
      || (type && TREE_CODE (type) == REFERENCE_TYPE))
    /* We used to check TYPE_NEEDS_CONSTRUCTING here, but now a constexpr
       constructor can produce constant init, so rely on cp_finish_decl to
       clear TREE_READONLY if the variable has non-constant init.  */
    TREE_READONLY (decl) = 1;

The comments referencing constexpr suggest that TREE_READONLY should perhaps be set here and then cleared in cp_finish_decl.

$ cat z.c && /home/msebor/build/gcc-trunk-svn/gcc/xgcc -B/home/msebor/build/gcc-trunk-svn/gcc -Wall -Wextra -Wpedantic -xc++ z.c
template <typename>
struct S {
    int i;
};

struct T {
    static constexpr S<int> s = { 1 };
};

int main()
{
    return T::s.i;
}
/tmp/ccqP3dAP.o: In function `main':
z.c:(.text+0x6): undefined reference to `T::s'
collect2: error: ld returned 1 exit status
Comment 2 Martin Sebor 2016-03-09 22:10:16 UTC
Patch posted for review:
https://gcc.gnu.org/ml/gcc-patches/2016-03/msg00593.html
Comment 3 Paolo Carlini 2017-09-22 13:12:58 UTC
Hi Martin. Are you still actively working on this? Because something implementing as trivially as the below what Jason suggested on the mailing list already appears to pass testing, shouldn't be *that* far from an actual fix...

Index: decl.c
===================================================================
--- decl.c      (revision 253091)
+++ decl.c      (working copy)
@@ -12348,7 +12348,11 @@
 
     /* Set constexpr flag on vars (functions got it in grokfndecl).  */
     if (constexpr_p && VAR_P (decl))
-      DECL_DECLARED_CONSTEXPR_P (decl) = true;
+      {
+       DECL_DECLARED_CONSTEXPR_P (decl) = true;
+       if (!processing_template_decl)
+         complete_type (TREE_TYPE (decl));
+      }
 
     /* Record constancy and volatility on the DECL itself .  There's
        no need to do this when processing a template; we'll do this
Comment 4 Martin Sebor 2017-09-22 16:18:43 UTC
(In reply to Paolo Carlini from comment #3)

I'm not currently working on it.  Please feel free to assign the bug to yourself and submit your patch instead.
Comment 5 Paolo Carlini 2017-09-22 16:22:27 UTC
Thanks Martin.
Comment 6 paolo@gcc.gnu.org 2017-11-06 17:46:26 UTC
Author: paolo
Date: Mon Nov  6 17:45:55 2017
New Revision: 254461

URL: https://gcc.gnu.org/viewcvs?rev=254461&root=gcc&view=rev
Log:
/cp
2017-11-06  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/65579
	* decl2.c (finish_static_data_member_decl): If there's an initializer,
	complete the type and re-apply the quals.

/testsuite
2017-11-06  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/65579
	* g++.dg/cpp0x/constexpr-template11.C: New.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-template11.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/decl2.c
    trunk/gcc/testsuite/ChangeLog
Comment 7 Paolo Carlini 2017-11-06 17:47:32 UTC
Fixed.