Hi,

A rather long standing issue. The error-recovery problem is that, in various circumstances, we flag as erroneous a local variable declaration and then, when we need to come back to it later on, lookup_name doesn't find it, keeps looking and may find instead a completely unrelated non-variable declaration with the same name. In principle, we could probably set up things in such a way that during error-recovery the erroneous entity is found anyway, marked as erroneous of course, but I don't think we want to attempt that now... Thus, I'm proposing to just check for VAR_P in the relevant case of tsubst_copy and bail-out. Setting instead r = NULL_TREE and trying to continue works rather well but leads to duplicate diagnostics in some cases (eg, for template/crash131.C).

By the way, something else I actually tried is returning immediately from tsubst_expr when the tsubst call in case DECL_EXPR returns error_mark_node and then bail out immediately from the for loop over the STATEMENT_LIST. That also passes the testsuite, but, if you want, you can certainly notice that the loop over the statements ends early, for example we would not provide any diagnostics for an additional Y<f> y2; in template/crash131.C. Which interestingly is true for current clang too ;)

Tested x86_64-linux.

Thanks, Paolo.

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

/cp
2019-04-01  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/62207
        * pt.c (tsubst_copy): Deal with lookup_name not returing a variable.

/testsuite
2019-04-01  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/62207
        * g++.dg/template/crash130.C: New.
        * g++.dg/template/crash131.C: Likewise.
Index: cp/pt.c
===================================================================
--- cp/pt.c     (revision 270012)
+++ cp/pt.c     (working copy)
@@ -15579,12 +15579,23 @@ tsubst_copy (tree t, tree args, tsubst_flags_t com
            {
              /* First try name lookup to find the instantiation.  */
              r = lookup_name (DECL_NAME (t));
-             if (r && !is_capture_proxy (r))
+             if (r)
                {
-                 /* Make sure that the one we found is the one we want.  */
-                 tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
-                 if (ctx != DECL_CONTEXT (r))
-                   r = NULL_TREE;
+                 if (!VAR_P (r))
+                   {
+                     /* During error-recovery we may find a non-variable,
+                        even an OVERLOAD: just bail out and avoid ICEs and
+                        duplicate diagnostics (c++/62207).  */
+                     gcc_assert (seen_error ());
+                     return error_mark_node;
+                   }
+                 if (!is_capture_proxy (r))
+                   {
+                     /* Make sure the one we found is the one we want.  */
+                     tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
+                     if (ctx != DECL_CONTEXT (r))
+                       r = NULL_TREE;
+                   }
                }
 
              if (r)
@@ -15620,7 +15631,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t com
                    }
                  gcc_assert (cp_unevaluated_operand || TREE_STATIC (r)
                              || decl_constant_var_p (r)
-                             || errorcount || sorrycount);
+                             || seen_error ());
                  if (!processing_template_decl
                      && !TREE_STATIC (r))
                    r = process_outer_var_ref (r, complain);
Index: testsuite/g++.dg/template/crash130.C
===================================================================
--- testsuite/g++.dg/template/crash130.C        (nonexistent)
+++ testsuite/g++.dg/template/crash130.C        (working copy)
@@ -0,0 +1,15 @@
+// PR c++/62207
+
+template<typename T> void foo(T)
+{
+  X;  // { dg-error "not declared" }
+  X;
+}
+
+void X();
+void X(int);
+
+void bar()
+{
+  foo(0);
+}
Index: testsuite/g++.dg/template/crash131.C
===================================================================
--- testsuite/g++.dg/template/crash131.C        (nonexistent)
+++ testsuite/g++.dg/template/crash131.C        (working copy)
@@ -0,0 +1,16 @@
+// PR c++/62207
+
+template<class F>
+class X {
+public:
+  template<F f> class Y {};
+  template<F f> void y() {}
+  X(F f)
+  {
+    Y<f> y;  // { dg-error "not a constant" }
+
+    y.value();
+  }
+};
+
+int main() { X<int> x(1); }

Reply via email to