c++: C++17 constexpr static data member linkage [PR99901]

C++17 makes constexpr static data members implicitly inline variables.  In
C++14, a subsequent out-of-class declaration is the definition.  We want to
continue emitting a symbol for such a declaration in C++17 mode, for ABI
compatibility with C++14 code that wants to refer to it.

Normally I'd distinguish in- and out-of-class declarations by looking at
DECL_IN_AGGR_P, but we never set DECL_IN_AGGR_P on inline variables.  I
think that's wrong, but don't want to mess with it so close to release.
Conveniently, we already have a test for in-class declaration earlier in the
function.

gcc/cp/ChangeLog:

	PR c++/99901
	* decl.c (cp_finish_decl): mark_needed an implicitly inline
	static data member with an out-of-class redeclaration.

gcc/testsuite/ChangeLog:

	PR c++/99901
	* g++.dg/cpp1z/inline-var9.C: New test.
This commit is contained in:
Jason Merrill 2021-04-06 01:21:05 -04:00
parent 7ce3d2ab2a
commit 623842bead
2 changed files with 54 additions and 4 deletions

View File

@ -7010,10 +7010,13 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
if (asmspec_tree && asmspec_tree != error_mark_node)
asmspec = TREE_STRING_POINTER (asmspec_tree);
if (current_class_type
&& CP_DECL_CONTEXT (decl) == current_class_type
&& TYPE_BEING_DEFINED (current_class_type)
&& !CLASSTYPE_TEMPLATE_INSTANTIATION (current_class_type)
bool in_class_decl
= (current_class_type
&& CP_DECL_CONTEXT (decl) == current_class_type
&& TYPE_BEING_DEFINED (current_class_type)
&& !CLASSTYPE_TEMPLATE_INSTANTIATION (current_class_type));
if (in_class_decl
&& (DECL_INITIAL (decl) || init))
DECL_INITIALIZED_IN_CLASS_P (decl) = 1;
@ -7345,6 +7348,13 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
{
layout_var_decl (decl);
maybe_commonize_var (decl);
/* A class-scope constexpr variable with an out-of-class declaration.
C++17 makes them implicitly inline, but still force it out. */
if (DECL_INLINE_VAR_P (decl)
&& !DECL_VAR_DECLARED_INLINE_P (decl)
&& !DECL_TEMPLATE_INSTANTIATION (decl)
&& !in_class_decl)
mark_needed (decl);
}
/* This needs to happen after the linkage is set. */

View File

@ -0,0 +1,40 @@
// PR c++/99901
// { dg-do compile { target c++11 } }
// { dg-final { scan-assembler-not "_ZN1A1aE" } }
// { dg-final { scan-assembler-not "_ZN2A21aE" } }
// { dg-final { scan-assembler-not "_ZN1CIiE1cE" } }
// { dg-final { scan-assembler "_ZN1B1bE" } }
// { dg-final { scan-assembler "_ZN2B21bE" } }
// { dg-final { scan-assembler "_ZN2B31bE" } }
struct A {
static const int a = 5;
};
struct A2 {
static constexpr int a = 5;
};
struct B {
static const int b;
};
constexpr int B::b = 5;
struct B2 {
static const int b = 5;
};
constexpr int B2::b;
struct B3 {
static constexpr int b = 5;
};
const int B3::b;
template <class T>
struct C {
static constexpr int c = 5;
};
template <class T>
constexpr int C<T>::c;
int i = C<int>::c;