PR c++/81236 - ICE with template-id in generic lambda
authorJason Merrill <jason@redhat.com>
Tue, 29 Aug 2017 21:38:21 +0000 (17:38 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 29 Aug 2017 21:38:21 +0000 (17:38 -0400)
* semantics.c (finish_id_expression): Remove special dependent case.
Avoid some later pieces when dependent.
(finish_qualified_id_expr): Do normal BASELINK handling in a
template.  Always build a SCOPE_REF for a destructor BIT_NOT_EXPR.
(parsing_default_capturing_generic_lambda_in_template): Remove.
* parser.c (cp_parser_postfix_dot_deref_expression): Always give an
error for types that will never be complete.
* mangle.c (write_expression): Add sanity check.
* tree.c (build_qualified_name): Add sanity check.
(cp_walk_subtrees): Walk into the class context of a BASELINK.
* lambda.c (add_capture): Improve diagnostic for generic lambda
capture failure.
* call.c (build_new_method_call_1): Print the right constructor
name.

From-SVN: r251438

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/lambda.c
gcc/cp/mangle.c
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/pseudodtor3.C

index 6e1db068ebf3d4c12f5ad9a679d634fa5f776789..8532f57e91a3030a29488dfd8d9056d5c09fedc1 100644 (file)
@@ -1,5 +1,21 @@
 2017-08-29  Jason Merrill  <jason@redhat.com>
 
+       PR c++/81236 - ICE with template-id in generic lambda
+       * semantics.c (finish_id_expression): Remove special dependent case.
+       Avoid some later pieces when dependent.
+       (finish_qualified_id_expr): Do normal BASELINK handling in a
+       template.  Always build a SCOPE_REF for a destructor BIT_NOT_EXPR.
+       (parsing_default_capturing_generic_lambda_in_template): Remove.
+       * parser.c (cp_parser_postfix_dot_deref_expression): Always give an
+       error for types that will never be complete.
+       * mangle.c (write_expression): Add sanity check.
+       * tree.c (build_qualified_name): Add sanity check.
+       (cp_walk_subtrees): Walk into the class context of a BASELINK.
+       * lambda.c (add_capture): Improve diagnostic for generic lambda
+       capture failure.
+       * call.c (build_new_method_call_1): Print the right constructor
+       name.
+
        Reimplement handling of lambdas in templates.
        * cp-tree.h (LAMBDA_FUNCTION_P): Check DECL_DECLARES_FUNCTION_P.
        * decl.c (start_preparsed_function): Call start_lambda_scope.
index f7f929780529d290fcd9e2de4a8f190e9ef5f93e..c446057cfba7b1b193dd137b1c29e7ba7e3d6300 100644 (file)
@@ -9007,6 +9007,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
       if (! (complain & tf_error))
        return error_mark_node;
 
+      basetype = DECL_CONTEXT (fn);
       name = constructor_name (basetype);
       if (permerror (input_location,
                     "cannot call constructor %<%T::%D%> directly",
index 4747a727173f4dd7a17e70f622f16f7c05e2da3a..9ba3df10363c90ec89b61514aa0357d2771e3d64 100644 (file)
@@ -590,7 +590,11 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
   /* Add it to the appropriate closure class if we've started it.  */
   if (current_class_type
       && current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
-    finish_member_declaration (member);
+    {
+      if (COMPLETE_TYPE_P (current_class_type))
+       internal_error ("trying to capture %qD after closure is complete", id);
+      finish_member_declaration (member);
+    }
 
   tree listmem = member;
   if (variadic)
index a87f97fdf9f08cc83bf83ebb386896c86f457570..ce7c0c51f0ae931988db8d93d6e709a868f0b091 100644 (file)
@@ -3015,6 +3015,7 @@ write_expression (tree expr)
        {
          scope = TREE_OPERAND (expr, 0);
          member = TREE_OPERAND (expr, 1);
+         gcc_assert (!BASELINK_P (member));
        }
       else
        {
index d0d71fa1dae1d5921c68e1689463a47e6639f5a0..47d91bfa9a79a78183c601b61cc213b2336c0c53 100644 (file)
@@ -7446,11 +7446,14 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
              /* In a template, be permissive by treating an object expression
                 of incomplete type as dependent (after a pedwarn).  */
              diagnostic_t kind = (processing_template_decl
+                                  && MAYBE_CLASS_TYPE_P (scope)
                                   ? DK_PEDWARN
                                   : DK_ERROR);
              cxx_incomplete_type_diagnostic
                (location_of (postfix_expression),
                 postfix_expression, scope, kind);
+             if (!MAYBE_CLASS_TYPE_P (scope))
+               return error_mark_node;
              if (processing_template_decl)
                {
                  dependent_p = true;
@@ -20671,33 +20674,6 @@ parsing_nsdmi (void)
   return false;
 }
 
-/* Return true iff our current scope is a default capturing generic lambda
-   defined within a template.  FIXME: This is part of a workaround (see
-   semantics.c) to handle building lambda closure types correctly in templates
-   which we ultimately want to defer to instantiation time. */
-
-bool
-parsing_default_capturing_generic_lambda_in_template (void)
-{
-  if (!processing_template_decl || !current_class_type)
-    return false;
-
-  tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type);
-  if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE)
-    return false;
-
-  tree callop = lambda_function (lam);
-  if (!callop)
-    return false;
-
-  return (DECL_TEMPLATE_INFO (callop)
-         && (DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop)
-         && ((current_nonlambda_class_type ()
-              && CLASSTYPE_TEMPLATE_INFO (current_nonlambda_class_type ()))
-             || ((current_nonlambda_function ()
-                  && DECL_TEMPLATE_INFO (current_nonlambda_function ())))));
-}
-
 /* Parse a late-specified return type, if any.  This is not a separate
    non-terminal, but part of a function declarator, which looks like
 
index 8f2822107d630f149daea695c6aa21445ae43e87..b2e58d2dbf056eb8d79f96f4512f6e03b6c0e138 100644 (file)
@@ -2035,7 +2035,7 @@ finish_qualified_id_expr (tree qualifying_class,
                                            qualifying_class);
       pop_deferring_access_checks ();
     }
-  else if (BASELINK_P (expr) && !processing_template_decl)
+  else if (BASELINK_P (expr))
     {
       /* See if any of the functions are non-static members.  */
       /* If so, the expression may be relative to 'this'.  */
@@ -2055,8 +2055,6 @@ finish_qualified_id_expr (tree qualifying_class,
        expr = build_offset_ref (qualifying_class, expr, /*address_p=*/false,
                                 complain);
     }
-  else if (BASELINK_P (expr))
-    ;
   else
     {
       /* In a template, return a SCOPE_REF for most qualified-ids
@@ -2065,7 +2063,8 @@ finish_qualified_id_expr (tree qualifying_class,
         know we have access and building up the SCOPE_REF confuses
         non-type template argument handling.  */
       if (processing_template_decl
-         && !currently_open_class (qualifying_class))
+         && (!currently_open_class (qualifying_class)
+             || TREE_CODE (expr) == BIT_NOT_EXPR))
        expr = build_qualified_name (TREE_TYPE (expr),
                                     qualifying_class, expr,
                                     template_p);
@@ -3595,78 +3594,12 @@ finish_id_expression (tree id_expression,
                    ? CP_ID_KIND_UNQUALIFIED_DEPENDENT
                    : CP_ID_KIND_UNQUALIFIED)));
 
-      /* If the name was dependent on a template parameter and we're not in a
-        default capturing generic lambda within a template, we will resolve the
-        name at instantiation time.  FIXME: For lambdas, we should defer
-        building the closure type until instantiation time then we won't need
-        the extra test here.  */
       if (dependent_p
-         && !parsing_default_capturing_generic_lambda_in_template ())
-       {
-         if (DECL_P (decl)
-             && any_dependent_type_attributes_p (DECL_ATTRIBUTES (decl)))
-           /* Dependent type attributes on the decl mean that the TREE_TYPE is
-              wrong, so just return the identifier.  */
-           return id_expression;
-
-         /* If we found a variable, then name lookup during the
-            instantiation will always resolve to the same VAR_DECL
-            (or an instantiation thereof).  */
-         if (VAR_P (decl)
-             || TREE_CODE (decl) == CONST_DECL
-             || TREE_CODE (decl) == PARM_DECL)
-           {
-             mark_used (decl);
-             return convert_from_reference (decl);
-           }
-
-         /* Create a SCOPE_REF for qualified names, if the scope is
-            dependent.  */
-         if (scope)
-           {
-             if (TYPE_P (scope))
-               {
-                 if (address_p && done)
-                   decl = finish_qualified_id_expr (scope, decl,
-                                                    done, address_p,
-                                                    template_p,
-                                                    template_arg_p,
-                                                    tf_warning_or_error);
-                 else
-                   {
-                     tree type = NULL_TREE;
-                     if (DECL_P (decl) && !dependent_scope_p (scope))
-                       type = TREE_TYPE (decl);
-                     decl = build_qualified_name (type,
-                                                  scope,
-                                                  id_expression,
-                                                  template_p);
-                   }
-               }
-             if (TREE_TYPE (decl))
-               decl = convert_from_reference (decl);
-             return decl;
-           }
-         /* A TEMPLATE_ID already contains all the information we
-            need.  */
-         if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
-           return id_expression;
-         /* The same is true for FIELD_DECL, but we also need to
-            make sure that the syntax is correct.  */
-         else if (TREE_CODE (decl) == FIELD_DECL)
-           {
-             /* Since SCOPE is NULL here, this is an unqualified name.
-                Access checking has been performed during name lookup
-                already.  Turn off checking to avoid duplicate errors.  */
-             push_deferring_access_checks (dk_no_check);
-             decl = finish_non_static_data_member
-                      (decl, NULL_TREE,
-                       /*qualifying_scope=*/NULL_TREE);
-             pop_deferring_access_checks ();
-             return decl;
-           }
-         return id_expression;
-       }
+         && DECL_P (decl)
+         && any_dependent_type_attributes_p (DECL_ATTRIBUTES (decl)))
+       /* Dependent type attributes on the decl mean that the TREE_TYPE is
+          wrong, so just return the identifier.  */
+       return id_expression;
 
       if (TREE_CODE (decl) == NAMESPACE_DECL)
        {
@@ -3700,6 +3633,7 @@ finish_id_expression (tree id_expression,
         expression.  Template parameters have already
         been handled above.  */
       if (! error_operand_p (decl)
+         && !dependent_p
          && integral_constant_expression_p
          && ! decl_constant_var_p (decl)
          && TREE_CODE (decl) != CONST_DECL
@@ -3726,6 +3660,7 @@ finish_id_expression (tree id_expression,
          decl = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
        }
       else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+              && !dependent_p
               && variable_template_p (TREE_OPERAND (decl, 0)))
        {
          decl = finish_template_variable (decl);
@@ -3734,6 +3669,12 @@ finish_id_expression (tree id_expression,
        }
       else if (scope)
        {
+         if (TREE_CODE (decl) == SCOPE_REF)
+           {
+             gcc_assert (same_type_p (scope, TREE_OPERAND (decl, 0)));
+             decl = TREE_OPERAND (decl, 1);
+           }
+
          decl = (adjust_result_of_qualified_name_lookup
                  (decl, scope, current_nonlambda_class_type()));
 
index dbac7f3c550161e8b246c3d6c6dda7efdb34c67f..aab92d5e9d5fb451b0e437cd9d3f43d0ad1f1c46 100644 (file)
@@ -2028,6 +2028,7 @@ build_qualified_name (tree type, tree scope, tree name, bool template_p)
       || scope == error_mark_node
       || name == error_mark_node)
     return error_mark_node;
+  gcc_assert (TREE_CODE (name) != SCOPE_REF);
   t = build2 (SCOPE_REF, type, scope, name);
   QUALIFIED_NAME_IS_TEMPLATE (t) = template_p;
   PTRMEM_OK_P (t) = true;
@@ -4663,6 +4664,8 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
       break;
 
     case BASELINK:
+      if (BASELINK_QUALIFIED_P (*tp))
+       WALK_SUBTREE (BINFO_TYPE (BASELINK_ACCESS_BINFO (*tp)));
       WALK_SUBTREE (BASELINK_FUNCTIONS (*tp));
       *walk_subtrees_p = 0;
       break;
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C
new file mode 100644 (file)
index 0000000..52d25af
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/81236
+// { dg-do compile { target c++14 } }
+
+struct A { constexpr operator int() { return 24; } };
+
+struct MyType {
+  void crash() {
+    auto l = [&](auto i){
+      make_crash<i>(); // Line (1)
+    };
+
+    l(A{});
+  }
+    
+  template<int i>
+  void make_crash() {}
+};
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C
new file mode 100644 (file)
index 0000000..d321a07
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/81236
+// { dg-do compile { target c++14 } }
+
+struct A { constexpr operator int() { return 24; } };
+
+struct MyType {
+  void crash() {
+    auto l = [&](auto i){
+      MyType::make_crash<i>(); // Line (1)
+    };
+
+    l(A{});
+  }
+    
+  template<int i>
+  void make_crash() {}
+};
index 8f1f6a736a8e7abe6a37d81da10f17a629e775da..21a68aaac45f83f4076a3231a50afac0397c99b3 100644 (file)
@@ -11,7 +11,7 @@ struct A
 template <typename T> struct B
 {
   T &foo ();
-  B () { foo.~T (); }  // { dg-error "15:invalid use of member" }
+  B () { foo.~T (); }  // { dg-error "10:invalid use of member" }
 };
 
 B<int> b;
@@ -37,7 +37,7 @@ template <typename T> struct E
 {
   T &foo ();
   typedef long int U;
-  E () { foo.~U (); }  // { dg-error "10:is not of type" }
+  E () { foo.~U (); }  // { dg-error "10:invalid use of member" }
 };
 
 E<int> e;