Hi,

On 19/02/19 00:52, Jason Merrill wrote:
On 2/18/19 12:14 PM, Paolo Carlini wrote:
Hi Jason,

On 18/02/19 19:28, Jason Merrill wrote:
On 2/18/19 5:31 AM, Paolo Carlini wrote:
Hi Jason,

On 18/02/19 10:20, Jason Merrill wrote:
On 2/17/19 6:58 AM, Paolo Carlini wrote:
Hi,

here, when we don't see an initializer we believe we are surely dealing with a case of C++17 template argument deduction for class templates, but, in fact, it's just an ill-formed C++14 template variable specialization. Conveniently, we can use here too the predicate variable_template_specialization_p. Not 100% sure about the exact wording of the error message, I added '#' to %qD to explicitly print the auto-using type too.

I guess we should change the assert to a test, so that we give the error if we aren't dealing with a class template placeholder. Variable templates don't seem to be important to test for.
Thanks, simpler patch.
This error is also pretty poor for this testcase, where there is an initializer.

Well, implementation-wise, certainly init == NULL_TREE and only when we have an empty pack this specific issue occurs.

In practice, clang simply talks about an empty initializer (during instantiation, etc, like we do), whereas EDG explicitly says that pack expansion produces an empty list of expressions. I don't think that in cp_finish_decl it would be easy for us to do exactly the same, we simply see a NULL_TREE as second argument. Or we could just *assume* that we are dealing with the outcome of a pack expansion, say something like EDG even if we don't have details beyond the fact that init == NULL_TREE. I believe that without a variadic template the problem cannot occur, because we catch the empty initializer much earlier, in grokdeclarator - indeed using a !CLASS_PLACEHOLDER_TEMPLATE (auto_node) check. What do you think? Again "instantiated for an empty pack" or something similar?

Perhaps we could complain in the code for empty pack expansion handling in tsubst_init?

Ah, thanks Jason. In fact, however, tsubst_init isn't currently involved at all, because, at the end of regenerate_decl_from_template we call by hand tsubst_expr and assign the result to DECL_INITIAL. Simply changing that avoids the ICE. However, the error we issue - likewise for the existing cpp0x/auto31.C - is the rather user-unfriendly "value-initialization of incomplete type ‘auto’", as produced by build_value_init. Thus a simple additional test along the lines already discussed, which now becomes much more simple to implement in a precise way. Again, wording only tentative. I'm also a little puzzled that, otherwise, we could get away with tubst_expr instead of tsubst_init...

+      if (type_uses_auto (TREE_TYPE (decl)))
+    {
+      if (complain & tf_error)
+        error ("initializer for %q#D expands to an empty list "
+           "of expressions", decl);
+      return error_mark_node;
+    }

This needs to allow the CLASS_PLACEHOLDER_TEMPLATE case.

And yes, we mustn't call build_value_init for a dependent type; if the type is dependent, we should just return the NULL_TREE.

Good. Then I'm finishing testing the below (currently in libstdc++).

Thanks, Paolo.

//////////////////

Index: cp/pt.c
===================================================================
--- cp/pt.c     (revision 268997)
+++ cp/pt.c     (working copy)
@@ -15422,21 +15422,34 @@ tsubst_init (tree init, tree decl, tree args,
 
   init = tsubst_expr (init, args, complain, in_decl, false);
 
-  if (!init && TREE_TYPE (decl) != error_mark_node)
+  tree type = TREE_TYPE (decl);
+
+  if (!init && type != error_mark_node)
     {
-      /* If we had an initializer but it
-        instantiated to nothing,
-        value-initialize the object.  This will
-        only occur when the initializer was a
-        pack expansion where the parameter packs
-        used in that expansion were of length
-        zero.  */
-      init = build_value_init (TREE_TYPE (decl),
-                              complain);
-      if (TREE_CODE (init) == AGGR_INIT_EXPR)
-       init = get_target_expr_sfinae (init, complain);
-      if (TREE_CODE (init) == TARGET_EXPR)
-       TARGET_EXPR_DIRECT_INIT_P (init) = true;
+      if (tree auto_node = type_uses_auto (type))
+       if (!CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+         {
+           if (complain & tf_error)
+             error ("initializer for %q#D expands to an empty list "
+                    "of expressions", decl);
+           return error_mark_node;
+         }
+
+      if (!dependent_type_p (type))
+       {
+         /* If we had an initializer but it
+            instantiated to nothing,
+            value-initialize the object.  This will
+            only occur when the initializer was a
+            pack expansion where the parameter packs
+            used in that expansion were of length
+            zero.  */
+         init = build_value_init (type, complain);
+         if (TREE_CODE (init) == AGGR_INIT_EXPR)
+           init = get_target_expr_sfinae (init, complain);
+         if (TREE_CODE (init) == TARGET_EXPR)
+           TARGET_EXPR_DIRECT_INIT_P (init) = true;
+       }
     }
 
   return init;
@@ -24053,9 +24066,8 @@ regenerate_decl_from_template (tree decl, tree tmp
     {
       start_lambda_scope (decl);
       DECL_INITIAL (decl) =
-       tsubst_expr (DECL_INITIAL (code_pattern), args,
-                    tf_error, DECL_TI_TEMPLATE (decl),
-                    /*integral_constant_expression_p=*/false);
+       tsubst_init (DECL_INITIAL (code_pattern), decl, args,
+                    tf_error, DECL_TI_TEMPLATE (decl));
       finish_lambda_scope ();
       if (VAR_HAD_UNKNOWN_BOUND (decl))
        TREE_TYPE (decl) = tsubst (TREE_TYPE (code_pattern), args,
Index: testsuite/g++.dg/cpp1y/var-templ60.C
===================================================================
--- testsuite/g++.dg/cpp1y/var-templ60.C        (nonexistent)
+++ testsuite/g++.dg/cpp1y/var-templ60.C        (working copy)
@@ -0,0 +1,9 @@
+// PR c++/84536
+// { dg-do compile { target c++14 } }
+
+template<int... N> auto foo(N...);  // { dg-error "initializer" }
+
+void bar()
+{
+  foo<>();
+}

Reply via email to