c++: Immediately deduce auto member [PR94926].
authorJason Merrill <jason@redhat.com>
Thu, 28 May 2020 04:35:56 +0000 (00:35 -0400)
committerJason Merrill <jason@redhat.com>
Thu, 28 May 2020 18:58:16 +0000 (14:58 -0400)
In r9-297 I was trying to be more flexible and treat static data members of
class templates more like variable templates, where the type need not be
determined until the variable is instantiated, but I suppose that in a class
the types of all the non-template members need to be determined at the time
of class instantiation.

gcc/cp/ChangeLog:

PR c++/94926
* decl.c (cp_finish_decl): Revert r9-297 change.
(check_static_variable_definition): Likewise.
* constexpr.c (ensure_literal_type_for_constexpr_object): Likewise.
* pt.c (instantiate_decl): Return early on type error.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/pr86648.C: Expect error.
* g++.dg/cpp1z/static2.C: Expect error.
* g++.dg/cpp0x/nsdmi16.C: New test.

gcc/cp/constexpr.c
gcc/cp/decl.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/nsdmi16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/pr86648.C
gcc/testsuite/g++.dg/cpp1z/static2.C

index 4e441ac8d2fa0c209a742b7bfb0b38035fb1dac4..4b1f92f989cf7163870b41181f7f1c186537ecde 100644 (file)
@@ -96,8 +96,6 @@ ensure_literal_type_for_constexpr_object (tree decl)
       if (CLASS_TYPE_P (stype) && !COMPLETE_TYPE_P (complete_type (stype)))
        /* Don't complain here, we'll complain about incompleteness
           when we try to initialize the variable.  */;
-      else if (type_uses_auto (type))
-       /* We don't know the actual type yet.  */;
       else if (!literal_type_p (type))
        {
          if (DECL_DECLARED_CONSTEXPR_P (decl))
index 56571e39570892741b4fe6c59323b2379df79ea2..b0de90630d7c6e00dda8349011cfa14ec542437b 100644 (file)
@@ -7467,18 +7467,24 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
       && (DECL_INITIAL (decl) || init))
     DECL_INITIALIZED_IN_CLASS_P (decl) = 1;
 
-  /* Do auto deduction unless decl is a function or an uninstantiated
-     template specialization.  */
   if (TREE_CODE (decl) != FUNCTION_DECL
-      && !(init == NULL_TREE
-          && DECL_LANG_SPECIFIC (decl)
-          && DECL_TEMPLATE_INSTANTIATION (decl)
-          && !DECL_TEMPLATE_INSTANTIATED (decl))
       && (auto_node = type_uses_auto (type)))
     {
       tree d_init;
       if (init == NULL_TREE)
-       gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (auto_node));
+       {
+         if (DECL_LANG_SPECIFIC (decl)
+             && DECL_TEMPLATE_INSTANTIATION (decl)
+             && !DECL_TEMPLATE_INSTANTIATED (decl))
+           {
+             /* init is null because we're deferring instantiating the
+                initializer until we need it.  Well, we need it now.  */
+             instantiate_decl (decl, /*defer_ok*/true, /*expl*/false);
+             return;
+           }
+
+         gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (auto_node));
+       }
       d_init = init;
       if (d_init)
        {
@@ -10171,7 +10177,6 @@ check_static_variable_definition (tree decl, tree type)
      in check_initializer.  Similarly for inline static data members.  */
   else if (DECL_P (decl)
       && (DECL_DECLARED_CONSTEXPR_P (decl)
-         || undeduced_auto_decl (decl)
          || DECL_VAR_DECLARED_INLINE_P (decl)))
     ;
   else if (cxx_dialect >= cxx11 && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
index 4d9651acee65be392a53fc004cbb9cb94c0ed88d..90dafff3aa700ab29d8467e0e9175e49ca2b6ac9 100644 (file)
@@ -25293,6 +25293,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
     d = DECL_CLONED_FUNCTION (d);
 
   if (DECL_TEMPLATE_INSTANTIATED (d)
+      || TREE_TYPE (d) == error_mark_node
       || (TREE_CODE (d) == FUNCTION_DECL
          && DECL_DEFAULTED_FN (d) && DECL_INITIAL (d))
       || DECL_TEMPLATE_SPECIALIZATION (d))
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi16.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi16.C
new file mode 100644 (file)
index 0000000..07bc198
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/94926
+// { dg-do compile { target c++11 } }
+
+template<typename>
+struct A {
+    static auto self_reference = A{}; // { dg-error "incomplete" }
+};
+
+int main() {
+    A<void>{};
+}
index 20ee4c8c0d4465014b9199f0cf501939c94d44df..58c611c985fc255120ed09a35fec837d433c5cb4 100644 (file)
@@ -1,5 +1,7 @@
 // { dg-do compile { target c++17 } }
 
 template <typename> class A;
-template <class T> struct B { static A a{T::a}; };
+template <class T> struct B {
+  static A a{T::a};            // { dg-error "int" }
+};
 void foo () { B<int> a; }
index 9462e0355c8684ea7564703a3bc0b582b0b3ab78..5d93a0e7242bdb87fce4a4f6da9142c04dd2cdea 100644 (file)
@@ -3,7 +3,7 @@
 template <class T>
 struct A
 {
-  static constexpr auto x = T::x;
+  static constexpr auto x = T::x; // { dg-error "incomplete" }
 };
 
 struct B;