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:
parent
d48f87d5c1
commit
8685348075
@ -7693,10 +7693,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;
|
||||
|
||||
@ -8069,6 +8072,13 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
||||
if (!flag_weak)
|
||||
/* Check again now that we have an initializer. */
|
||||
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);
|
||||
}
|
||||
|
||||
if (var_definition_p
|
||||
|
40
gcc/testsuite/g++.dg/cpp1z/inline-var9.C
Normal file
40
gcc/testsuite/g++.dg/cpp1z/inline-var9.C
Normal 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;
|
Loading…
Reference in New Issue
Block a user