The problem here was that normally in finish_id_expression we add
'this->' to a mention of a non-static member, but there is special
code for doing less if the lookup result is dependent, and so we
didn't get that processing.

A few months back Adam fixed 64382 by deciding to do all the normal
processing if we're in a generic lambda in a template, but in this
testcase the generic lambda isn't in a template.

We could approach this by extending that change to all generic
lambdas, and that might be appropriate for GCC 7, but it seems to me
that this approach will just mean any problems with doing all the
normal processing in a template will remain latent until someone
happens to use them in a generic lambda; instead, this patch removes
the template special case and fixes the normal code to work properly
in templates.

The cp_parser_postfix_dot_deref_expression hunk was a latent
diagnostic quality issue: there's no point in trying to be permissive
about an incomplete type like void, since it can't be completed by
instantiation time.

The cp_walk_subtrees hunk was necessary to make abi-tag21.C work with
this change; without walking into the scope of the BASELINK, we didn't
see the explicit scope in the return type of fv.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 28df39b2192b5feeffa6dd2b8208cf0270ac5330
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Aug 24 14:09:01 2017 -0400

            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.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index f7f9297..c446057 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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",
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 4747a72..9ba3df1 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -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)
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index a87f97f..ce7c0c5 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3015,6 +3015,7 @@ write_expression (tree expr)
        {
          scope = TREE_OPERAND (expr, 0);
          member = TREE_OPERAND (expr, 1);
+         gcc_assert (!BASELINK_P (member));
        }
       else
        {
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d0d71fa..47d91bf 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 8f28221..b2e58d2 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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()));
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index dbac7f3..aab92d5 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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
index 0000000..52d25af
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1.C
@@ -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
index 0000000..d321a07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this1a.C
@@ -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() {}
+};
diff --git a/gcc/testsuite/g++.dg/template/pseudodtor3.C 
b/gcc/testsuite/g++.dg/template/pseudodtor3.C
index 8f1f6a7..21a68aa 100644
--- a/gcc/testsuite/g++.dg/template/pseudodtor3.C
+++ b/gcc/testsuite/g++.dg/template/pseudodtor3.C
@@ -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;

Reply via email to