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
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
Patch posted for review: https://gcc.gnu.org/ml/gcc-patches/2016-03/msg00593.html
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
(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.
Thanks Martin.
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
Fixed.