Hi! On the following testcase, we emit 2 errors and 1 warning, when the user really should see one error. The desirable error is static_assert failure, the bogus error is during error recovery, complaining that a no_linkage template isn't defined when it really is defined, but we haven't bothered instantiating it, because limit_bad_template_recursion sad so. And finally a warning from the middle-end about function being used even when it is not defined.
The last one already checks TREE_NO_WARNING on the function decl to avoid the warning, so this patch just uses TREE_NO_WARNING to signal this case, both to that warning and to no_linkage_error. Now, I admit I'm not 100% sure if using TREE_NO_WARNING is the best thing for no_linkage_error, another possibility might be adding some bit in lang_decl_base or so and setting that bit in addition to TREE_NO_WARNING, where that new bit would mean this decl might be defined if we didn't decide not to instantiate it. With the patch as is, there is a risk if TREE_NO_WARNING is set for some other reason on a fndecl (or variable template instantiation?) and some errors have been reported already that we won't report another error for it when we should. But perhaps that is acceptable, once users fix the original errors even if TREE_NO_WARNING will be set, errorcount + sorrycount will be zero and thus no_linkage_error will still report it. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? Or do you want to use an additional bit for that? 2019-12-10 Jakub Jelinek <ja...@redhat.com> PR c++/59655 * pt.c (push_tinst_level_loc): If limit_bad_template_recursion, set TREE_NO_WARNING on tldcl. * decl2.c (no_linkage_error): Treat templates with TREE_NO_WARNING as defined during error recovery. * g++.dg/cpp0x/diag3.C: New test. --- gcc/cp/pt.c.jj 2019-12-10 00:52:39.017449262 +0100 +++ gcc/cp/pt.c 2019-12-10 19:20:11.046062705 +0100 @@ -10640,7 +10640,12 @@ push_tinst_level_loc (tree tldcl, tree t anything else. Do allow deduction substitution and decls usable in constant expressions. */ if (!targs && limit_bad_template_recursion (tldcl)) - return false; + { + /* Avoid no_linkage_errors and unused function warnings for this + decl. */ + TREE_NO_WARNING (tldcl) = 1; + return false; + } /* When not -quiet, dump template instantiations other than functions, since announce_function will take care of those. */ --- gcc/cp/decl2.c.jj 2019-11-28 09:05:13.376262983 +0100 +++ gcc/cp/decl2.c 2019-12-10 19:33:05.555237052 +0100 @@ -4414,7 +4414,14 @@ decl_maybe_constant_var_p (tree decl) void no_linkage_error (tree decl) { - if (cxx_dialect >= cxx11 && decl_defined_p (decl)) + if (cxx_dialect >= cxx11 + && (decl_defined_p (decl) + /* Treat templates which limit_bad_template_recursion decided + not to instantiate as if they were defined. */ + || (errorcount + sorrycount > 0 + && DECL_LANG_SPECIFIC (decl) + && DECL_TEMPLATE_INFO (decl) + && TREE_NO_WARNING (decl)))) /* In C++11 it's ok if the decl is defined. */ return; tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false); --- gcc/testsuite/g++.dg/cpp0x/diag3.C.jj 2019-12-10 19:39:06.659722663 +0100 +++ gcc/testsuite/g++.dg/cpp0x/diag3.C 2019-12-10 19:37:30.617189316 +0100 @@ -0,0 +1,20 @@ +// PR c++/59655 +// { dg-do compile { target c++11 } } + +template<typename T> struct A { static constexpr bool value = false; }; + +struct B { + template<typename T> + B (T t) + { + static_assert (A<T>::value, "baz"); // { dg-error "static assertion failed" } + foo (t); + } + template<typename T> void foo (T) {} // { dg-bogus "used but never defined" } +}; + +int +main () +{ + B t([](int) { }); +} Jakub