aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/pt.cc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2024-08-06 20:54:03 -0400
committerPatrick Palka <ppalka@redhat.com>2024-08-06 20:54:03 -0400
commit596d1ed9d40b1081fcc6c6161a0135952829b88f (patch)
treeface5620e56b404afb00a16b3238e9b87944308c /gcc/cp/pt.cc
parentb120ca0c1da1a2f6e471edf61b18481296b464be (diff)
downloadgcc-596d1ed9d40b1081fcc6c6161a0135952829b88f.zip
gcc-596d1ed9d40b1081fcc6c6161a0135952829b88f.tar.gz
gcc-596d1ed9d40b1081fcc6c6161a0135952829b88f.tar.bz2
c++: permit errors inside uninstantiated templates [PR116064]
In recent versions of GCC we've been diagnosing more and more kinds of errors inside a template ahead of time. This is a largely good thing because it catches bugs, typos, dead code etc sooner. But if the template never gets instantiated then such errors are harmless and can be inconvenient to work around if say the code in question is third party and in maintenance mode. So it'd be handy to be able to prevent these template errors from rendering the entire TU uncompilable. (Note that such code is "ill-formed no diagnostic required" according the standard.) To that end this patch turns any errors issued within a template into permerrors associated with a new -Wtemplate-body flag so that they can be downgraded via e.g. -fpermissive or -Wno-error=template-body. If the template containing a downgraded error later needs to be instantiated, we'll issue an error then. But if the template never gets instantiated then the downgraded error won't affect validity of the rest of the TU. This is implemented via a diagnostic hook that gets called for each diagnostic, and which adjusts an error diagnostic appropriately if we detect it's occurring from a template context, and additionally flags the template as erroneous. For example the new testcase permissive-error1a.C gives: gcc/testsuite/g++.dg/template/permissive-error1a.C: In function 'void f()': gcc/testsuite/g++.dg/template/permissive-error1a.C:7:5: warning: increment of read-only variable 'n' [-Wtemplate-body] 7 | ++n; | ^ ... gcc/testsuite/g++.dg/template/permissive-error1a.C: In instantiation of 'void f() [with T = int]': gcc/testsuite/g++.dg/template/permissive-error1a.C:26:9: required from here 26 | f<int>(); | ~~~~~~^~ gcc/testsuite/g++.dg/template/permissive-error1a.C:5:6: error: instantiating erroneous template 5 | void f() { | ^ gcc/testsuite/g++.dg/template/permissive-error1a.C:7:5: note: first error appeared here 7 | ++n; // { | ^ ... PR c++/116064 gcc/c-family/ChangeLog: * c.opt (Wtemplate-body): New warning. gcc/cp/ChangeLog: * cp-tree.h (erroneous_templates_t): Declare. (erroneous_templates): Declare. (cp_seen_error): Declare. (seen_error): #define to cp_seen_error. * error.cc (get_current_template): Define. (relaxed_template_errors): Define. (cp_adjust_diagnostic_info): Define. (cp_seen_error): Define. (cxx_initialize_diagnostics): Set diagnostic_context::m_adjust_diagnostic_info. * module.cc (finish_module_processing): Don't write the module if it contains an erroneous template. * pt.cc (maybe_diagnose_erroneous_template): Define. (instantiate_class_template): Call it. (instantiate_decl): Likewise. gcc/ChangeLog: * diagnostic.cc (diagnostic_context::initialize): Set m_adjust_diagnostic_info. (diagnostic_context::report_diagnostic): Call m_adjust_diagnostic_info. * diagnostic.h (diagnostic_context::m_adjust_diagnostic_info): New data member. * doc/invoke.texi (-Wno-template-body): Document. (-fpermissive): Mention -Wtemplate-body. gcc/testsuite/ChangeLog: * g++.dg/ext/typedef-init.C: Downgrade error inside template to warning due to -fpermissive. * g++.dg/pr84492.C: Likewise. * g++.old-deja/g++.pt/crash51.C: Remove unneeded dg-options. * g++.dg/template/permissive-error1.C: New test. * g++.dg/template/permissive-error1a.C: New test. * g++.dg/template/permissive-error1b.C: New test. * g++.dg/template/permissive-error1c.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc/cp/pt.cc')
-rw-r--r--gcc/cp/pt.cc22
1 files changed, 22 insertions, 0 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 677ed7d..9a4ff55 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -12289,6 +12289,24 @@ perform_instantiation_time_access_checks (tree tmpl, tree targs)
}
}
+/* If the template T that we're about to instantiate contained errors at
+ parse time that we downgraded into warnings or suppressed, diagnose the
+ error now to render the TU ill-formed (if the TU has not already been
+ deemed ill-formed by an earlier error). */
+
+static void
+maybe_diagnose_erroneous_template (tree t)
+{
+ if (erroneous_templates && !(seen_error) ())
+ if (location_t *error_loc = erroneous_templates->get (t))
+ {
+ auto_diagnostic_group d;
+ location_t decl_loc = location_of (t);
+ error_at (decl_loc, "instantiating erroneous template");
+ inform (*error_loc, "first error appeared here");
+ }
+}
+
tree
instantiate_class_template (tree type)
{
@@ -12358,6 +12376,8 @@ instantiate_class_template (tree type)
if (! push_tinst_level (type))
return type;
+ maybe_diagnose_erroneous_template (templ);
+
int saved_unevaluated_operand = cp_unevaluated_operand;
int saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
@@ -27251,6 +27271,8 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
}
}
+ maybe_diagnose_erroneous_template (td);
+
code_pattern = DECL_TEMPLATE_RESULT (td);
/* We should never be trying to instantiate a member of a class