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); }