aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-02-20 21:24:40 -0500
committerJason Merrill <jason@gcc.gnu.org>2019-02-20 21:24:40 -0500
commit752620bec6bd8c5139bdd8fccba471c5e7f27e19 (patch)
tree1eae758075f42772117bea1e986e6e41bb507cd4
parent556bef7efc20fd95c79303c055059a24dcb72a5b (diff)
downloadgcc-752620bec6bd8c5139bdd8fccba471c5e7f27e19.zip
gcc-752620bec6bd8c5139bdd8fccba471c5e7f27e19.tar.gz
gcc-752620bec6bd8c5139bdd8fccba471c5e7f27e19.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl.c8
-rw-r--r--gcc/cp/decl2.c14
-rw-r--r--gcc/cp/pt.c3
-rw-r--r--gcc/cp/typeck2.c3
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inline-var6.C16
7 files changed, 48 insertions, 13 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5367aae..63b0764 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ac36544..879712f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index acde010..612afba 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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. */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 18db79eb..b60110a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8c5a1b3..a212be8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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);
}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index af56632..b265ea0 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -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. */
diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var6.C b/gcc/testsuite/g++.dg/cpp1z/inline-var6.C
new file mode 100644
index 0000000..2773010
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inline-var6.C
@@ -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 {};
+}