PR c++/87921 - wrong error with inline static data member.

c_parse_final_cleanups checks DECL_IN_AGGR_P to avoid trying to emit a
static data member that has not been defined.  The inline variable patch
changed that to exempt inline variables.  But in this case we haven't
instantiated the variable yet, so we really don't have a definition.  This
patch changes inline variable handling such that DECL_IN_AGGR_P is not set
for a defined inline variable, so we can remove all the checks of
DECL_INLINE_VAR_P after DECL_IN_AGGR_P.

With that change we were failing on a static data member that had been
instantiated due to a use before we got around to processing it in
instantiate_class_template; we should detect that and avoid all the
finish_static_data_member_decl processing, which assumes that it is the
first time we're seeing the variable.

	* decl2.c (finish_static_data_member_decl): Don't set DECL_IN_AGGR_P
	for a non-template inline variable.  Do nothing for an
	already-instantiated variable.
	(c_parse_final_cleanups): Check DECL_IN_AGGR_P without
	DECL_INLINE_VAR_P.
	* decl.c (check_initializer): Likewise.
	(make_rtl_for_nonlocal_decl): Likewise.
	* pt.c (instantiate_decl): Likewise.
	* typeck2.c (store_init_value): Likewise.

From-SVN: r269064
This commit is contained in:
Jason Merrill 2019-02-20 21:24:40 -05:00 committed by Jason Merrill
parent 556bef7efc
commit 752620bec6
7 changed files with 48 additions and 13 deletions

View File

@ -1,3 +1,16 @@
2019-02-20 Jason Merrill <jason@redhat.com>
PR c++/87921 - wrong error with inline static data member.
* decl2.c (finish_static_data_member_decl): Don't set DECL_IN_AGGR_P
for a non-template inline variable. Do nothing for an
already-instantiated variable.
(c_parse_final_cleanups): Check DECL_IN_AGGR_P without
DECL_INLINE_VAR_P.
* decl.c (check_initializer): Likewise.
(make_rtl_for_nonlocal_decl): Likewise.
* pt.c (instantiate_decl): Likewise.
* typeck2.c (store_init_value): Likewise.
2019-02-20 Jakub Jelinek <jakub@redhat.com>
PR c++/89403

View File

@ -2956,8 +2956,8 @@ struct GTY(()) lang_decl {
/* Nonzero for _DECL means that this decl appears in (or will appear
in) as a member in a RECORD_TYPE or UNION_TYPE node. It is also for
detecting circularity in case members are multiply defined. In the
case of a VAR_DECL, it is also used to determine how program storage
should be allocated. */
case of a VAR_DECL, it means that no definition has been seen, even
if an initializer has been. */
#define DECL_IN_AGGR_P(NODE) (DECL_LANG_FLAG_3 (NODE))
/* Nonzero for a VAR_DECL means that the variable's initialization (if

View File

@ -6563,9 +6563,8 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
}
if (init_code
&& (DECL_IN_AGGR_P (decl)
&& DECL_INITIALIZED_IN_CLASS_P (decl)
&& !DECL_VAR_DECLARED_INLINE_P (decl)))
&& DECL_IN_AGGR_P (decl)
&& DECL_INITIALIZED_IN_CLASS_P (decl))
{
static int explained = 0;
@ -6633,8 +6632,7 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec)
external; it is only a declaration, and not a definition. */
if (init == NULL_TREE)
gcc_assert (DECL_EXTERNAL (decl)
|| !TREE_PUBLIC (decl)
|| DECL_INLINE_VAR_P (decl));
|| !TREE_PUBLIC (decl));
}
/* We don't create any RTL for local variables. */

View File

@ -744,6 +744,11 @@ finish_static_data_member_decl (tree decl,
tree asmspec_tree,
int flags)
{
if (DECL_TEMPLATE_INSTANTIATED (decl))
/* We already needed to instantiate this, so the processing in this
function is unnecessary/wrong. */
return;
DECL_CONTEXT (decl) = current_class_type;
/* We cannot call pushdecl here, because that would fill in the
@ -772,7 +777,12 @@ finish_static_data_member_decl (tree decl,
break;
}
DECL_IN_AGGR_P (decl) = 1;
if (DECL_INLINE_VAR_P (decl) && !DECL_TEMPLATE_INSTANTIATION (decl))
/* An inline variable is immediately defined, so don't set DECL_IN_AGGR_P.
Except that if decl is a template instantiation, it isn't defined until
instantiate_decl. */;
else
DECL_IN_AGGR_P (decl) = 1;
if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
&& TYPE_DOMAIN (TREE_TYPE (decl)) == NULL_TREE)
@ -4977,7 +4987,7 @@ c_parse_final_cleanups (void)
{
if (var_finalized_p (decl) || DECL_REALLY_EXTERN (decl)
/* Don't write it out if we haven't seen a definition. */
|| (DECL_IN_AGGR_P (decl) && !DECL_INLINE_VAR_P (decl)))
|| DECL_IN_AGGR_P (decl))
continue;
import_export_decl (decl);
/* If this static data member is needed, provide it to the

View File

@ -24395,8 +24395,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
{
deleted_p = false;
if (DECL_CLASS_SCOPE_P (code_pattern))
pattern_defined = (! DECL_IN_AGGR_P (code_pattern)
|| DECL_INLINE_VAR_P (code_pattern));
pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
else
pattern_defined = ! DECL_EXTERNAL (code_pattern);
}

View File

@ -843,8 +843,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
value = fold_non_dependent_expr (value);
if (DECL_DECLARED_CONSTEXPR_P (decl)
|| (DECL_IN_AGGR_P (decl)
&& DECL_INITIALIZED_IN_CLASS_P (decl)
&& !DECL_VAR_DECLARED_INLINE_P (decl)))
&& DECL_INITIALIZED_IN_CLASS_P (decl)))
{
/* Diagnose a non-constant initializer for constexpr variable or
non-inline in-class-initialized static data member. */

View File

@ -0,0 +1,16 @@
// PR c++/87921
// { dg-do compile { target c++17 } }
template <class H>
struct X
{
static inline long x[] = { 1L };
long foo () { return x[0]; }
};
void
bar ()
{
class L {};
X<L> v {};
}