C ObjC C++ ObjC++ Var(warn_tautological_compare) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn if a comparison always evaluates to true or false.
+Wtemplate-body
+C++ ObjC++ Var(warn_template_body) Warning Init(1)
+Diagnose errors when parsing a template.
+
Wtemplate-id-cdtor
C++ ObjC++ Var(warn_template_id_cdtor) Warning
Warn about simple-template-id in a constructor or destructor.
extern void qualified_name_lookup_error (tree, tree, tree,
location_t);
+using erroneous_templates_t
+ = hash_map<tree, location_t, simple_hashmap_traits<tree_decl_hash, location_t>>;
+extern erroneous_templates_t *erroneous_templates;
+
+extern bool cp_seen_error ();
+#define seen_error() cp_seen_error ()
+
/* in except.cc */
extern void init_terminate_fn (void);
extern void init_exception_processing (void);
deferred_printed_type m_type_b;
};
+/* Return the in-scope template that's currently being parsed, or
+ NULL_TREE otherwise. */
+
+static tree
+get_current_template ()
+{
+ if (scope_chain && in_template_context && !current_instantiation ())
+ if (tree ti = get_template_info (current_scope ()))
+ return TI_TEMPLATE (ti);
+
+ return NULL_TREE;
+}
+
+/* A map from TEMPLATE_DECLs that we've determined to be erroneous
+ at parse time to the location of the first error within. */
+
+erroneous_templates_t *erroneous_templates;
+
+/* Callback function diagnostic_context::m_adjust_diagnostic_info.
+
+ Errors issued when parsing a template are automatically treated like
+ permerrors associated with the -Wtemplate-body flag and can be
+ downgraded into warnings accordingly, in which case we'll still
+ issue an error if we later need to instantiate the template. */
+
+static void
+cp_adjust_diagnostic_info (diagnostic_context *context,
+ diagnostic_info *diagnostic)
+{
+ if (diagnostic->kind == DK_ERROR)
+ if (tree tmpl = get_current_template ())
+ {
+ diagnostic->option_index = OPT_Wtemplate_body;
+
+ if (context->m_permissive)
+ diagnostic->kind = DK_WARNING;
+
+ bool existed;
+ location_t &error_loc
+ = hash_map_safe_get_or_insert<false> (erroneous_templates,
+ tmpl, &existed);
+ if (!existed)
+ /* Remember that this template had a parse-time error so
+ that we'll ensure a hard error has been issued upon
+ its instantiation. */
+ error_loc = diagnostic->richloc->get_loc ();
+ }
+}
+
+/* A generalization of seen_error which also returns true if we've
+ permissively downgraded an error to a warning inside a template. */
+
+bool
+cp_seen_error ()
+{
+ if ((seen_error) ())
+ return true;
+
+ if (erroneous_templates)
+ if (tree tmpl = get_current_template ())
+ if (erroneous_templates->get (tmpl))
+ return true;
+
+ return false;
+}
+
/* CONTEXT->printer is a basic pretty printer that was constructed
presumably by diagnostic_initialize(), called early in the
compiler's initialization process (in general_init) Before the FE
diagnostic_starter (context) = cp_diagnostic_starter;
/* diagnostic_finalizer is already c_diagnostic_finalizer. */
diagnostic_format_decoder (context) = cp_printer;
+ context->m_adjust_diagnostic_info = cp_adjust_diagnostic_info;
pp_format_postprocessor (pp) = new cxx_format_postprocessor ();
}
cookie = new module_processing_cookie (cmi_name, tmp_name, fd, e);
- if (errorcount)
+ if (errorcount
+ /* Don't write the module if it contains an erroneous template. */
+ || (erroneous_templates
+ && !erroneous_templates->is_empty ()))
warning_at (state->loc, 0, "not writing module %qs due to errors",
state->get_flatname ());
else if (cookie->out.begin ())
}
}
+/* 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)
{
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;
}
}
+ maybe_diagnose_erroneous_template (td);
+
code_pattern = DECL_TEMPLATE_RESULT (td);
/* We should never be trying to instantiate a member of a class
m_warn_system_headers = false;
m_max_errors = 0;
m_internal_error = nullptr;
+ m_adjust_diagnostic_info = nullptr;
m_text_callbacks.m_begin_diagnostic = default_diagnostic_starter;
m_text_callbacks.m_start_span = default_diagnostic_start_span_fn;
m_text_callbacks.m_end_diagnostic = default_diagnostic_finalizer;
if (was_warning && m_inhibit_warnings)
return false;
+ if (m_adjust_diagnostic_info)
+ m_adjust_diagnostic_info (this, diagnostic);
+
if (diagnostic->kind == DK_PEDWARN)
{
diagnostic->kind = m_pedantic_errors ? DK_ERROR : DK_WARNING;
/* Client hook to report an internal error. */
void (*m_internal_error) (diagnostic_context *, const char *, va_list *);
+ /* Client hook to adjust properties of the given diagnostic that we're
+ about to issue, such as its kind. */
+ void (*m_adjust_diagnostic_info)(diagnostic_context *, diagnostic_info *);
+
private:
/* Client-supplied callbacks for working with options. */
struct {
-Wno-non-template-friend -Wold-style-cast
-Woverloaded-virtual -Wno-pmf-conversions -Wself-move -Wsign-promo
-Wsized-deallocation -Wsuggest-final-methods
--Wsuggest-final-types -Wsuggest-override -Wno-template-id-cdtor
+-Wsuggest-final-types -Wsuggest-override -Wno-template-body
+-Wno-template-id-cdtor
-Wno-terminate -Wno-vexing-parse -Wvirtual-inheritance
-Wno-virtual-move-assign -Wvolatile -Wzero-as-null-pointer-constant}
inactive inside a system header file, such as the STL, so one can still
use the STL. One may also use using directives and qualified names.
+@opindex Wtemplate-body
+@opindex Wno-template-body
+@item -Wno-template-body @r{(C++ and Objective-C++ only)}
+Disable diagnosing errors when parsing a template, and instead issue an
+error only upon instantiation of the template. This flag can also be
+used to downgrade such errors into warnings with @option{Wno-error=} or
+@option{-fpermissive}.
+
@opindex Wtemplate-id-cdtor
@opindex Wno-template-id-cdtor
@item -Wno-template-id-cdtor @r{(C++ and Objective-C++ only)}
-Wint-conversion @r{(C and Objective-C only)}
-Wnarrowing @r{(C++ and Objective-C++ only)}
-Wreturn-mismatch @r{(C and Objective-C only)}
+-Wtemplate-body @r{(C++ and Objective-C++ only)}
}
The @option{-fpermissive} option is the default for historic C language
template<int> void foo()
{
- typedef int i = 0; /* { dg-error "is initialized" } */
+ typedef int i = 0; /* { dg-warning "is initialized" } */
}
template<int> int foo()
{
- return ({ foo; }); // { dg-error "insufficient context" }
+ return ({ foo; }); // { dg-warning "insufficient context" }
}
int bar()
}
bool g(int)
{
- return ({ g; }); // { dg-error "insufficient context" }
+ return ({ g; }); // { dg-warning "insufficient context" }
}
};
--- /dev/null
+// PR c++/116064
+// { dg-additional-options -fpermissive }
+
+template<class T>
+void f() {
+ const int n = 42;
+ ++n; // { dg-warning "read-only" }
+}
+
+template<class T>
+struct A {
+ void f(typename A::type); // { dg-warning "does not name a type" }
+};
+
+template<class T>
+struct B {
+ void f() {
+ this->g(); // { dg-warning "no member" }
+ }
+};
--- /dev/null
+// PR c++/116064
+// { dg-additional-options -fpermissive }
+// Like permissive-error1.C but verify instantiating the errorneous
+// templates gives an error after all.
+
+template<class T>
+void f() { // { dg-error "instantiating erroneous template" }
+ const int n = 42;
+ ++n; // { dg-warning "read-only variable 'n' .-Wtemplate-body." }
+ // { dg-message "first error appeared here" "" { target *-*-* } .-1 }
+ // { dg-error "read-only variable 'n'\[\n\r\]" "" { target *-*-* } .-2 }
+}
+
+template<class T>
+struct A {
+ void f(typename A::type); // { dg-warning "does not name a type" }
+};
+
+template<class T>
+struct B {
+ void f() {
+ this->g(); // { dg-warning "no member" }
+ }
+};
+
+int main() {
+ f<int>(); // { dg-message "required from here" }
+ A<int> a;
+ B<int> b;
+ b.f();
+}
--- /dev/null
+// PR c++/116064
+// { dg-additional-options -Wno-template-body }
+// Like permissive-error1a.C but verify -Wno-template-body suppresses
+// diagnostics.
+
+template<class T>
+void f() { // { dg-error "instantiating erroneous template" }
+ const int n = 42;
+ ++n; // { dg-message "first error appeared here" "" { target *-*-* } }
+ // { dg-error "read-only variable 'n'\[\n\r\]" "" { target *-*-* } .-1 }
+}
+
+template<class T>
+struct A {
+ void f(typename A::type);
+};
+
+template<class T>
+struct B {
+ void f() {
+ this->g();
+ }
+};
+
+int main() {
+ f<int>(); // { dg-message "required from here" }
+ A<int> a;
+ B<int> b;
+ b.f();
+}
--- /dev/null
+// PR c++/116064
+// { dg-additional-options -Wno-error=template-body }
+// Like permissive-error1a.C but verify the diagnostics can also
+// be downgraded via Wno-error=template-body.
+
+template<class T>
+void f() { // { dg-error "instantiating erroneous template" }
+ const int n = 42;
+ ++n; // { dg-warning "read-only variable 'n' .-Wtemplate-body." }
+ // { dg-message "first error appeared here" "" { target *-*-* } .-1 }
+ // { dg-error "read-only variable 'n'\[\n\r\]" "" { target *-*-* } .-2 }
+}
+
+template<class T>
+struct A {
+ void f(typename A::type); // { dg-warning "does not name a type" }
+};
+
+template<class T>
+struct B {
+ void f() {
+ this->g(); // { dg-warning "no member" }
+ }
+};
+
+int main() {
+ f<int>(); // { dg-message "required from here" }
+ A<int> a;
+ B<int> b;
+ b.f();
+}
// { dg-do assemble }
-// { dg-options "-fpermissive -w" }
// Origin: Mark Mitchell <mark@codesourcery.com>
char foo[26];