PR c++/87921 - wrong error with inline static data member.
authorJason Merrill <jason@redhat.com>
Thu, 21 Feb 2019 02:24:40 +0000 (21:24 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 21 Feb 2019 02:24:40 +0000 (21:24 -0500)
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

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/pt.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp1z/inline-var6.C [new file with mode: 0644]

index 5367aae5cc1bcf62f2deaf8e28476720c41ed401..63b07648776723dfdf6688577cc3be03a371d600 100644 (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
index ac3654467aceb8e449f3153cb16412e424f87877..879712f6dbce7c678f01e56c42f9250705bd44b2 100644 (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
index acde010e3e529e7c5291dbaba831d9198670a00b..612afbacd270ea78eec324f1afcff352536d0887 100644 (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.  */
index 18db79eb4f9ace9a50196fe489dd7fcc8a878d65..b60110a28652608e01b2edec3d3559f81ba54550 100644 (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
index 8c5a1b312fc89046bb9f985a2258dd267a234ea1..a212be8c7475f7d3d097e3a4d3a2558d5bc425e9 100644 (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);
     }
index af56632c0fc3ceae54a699e99069cc4934429bb1..b265ea057416241360066c53d288dab6bea233bc 100644 (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.  */
diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var6.C b/gcc/testsuite/g++.dg/cpp1z/inline-var6.C
new file mode 100644 (file)
index 0000000..2773010
--- /dev/null
@@ -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 {};
+}