#include "analyzer/pending-diagnostic.h"
#include "analyzer/call-details.h"
#include "make-unique.h"
+#include "pretty-print-markup.h"
#if ENABLE_ANALYZER
probably most user-friendly. */
escaped_decls.qsort (cmp_decls_ptr_ptr);
- pretty_printer pp;
- pp_format_decoder (&pp) = default_tree_printer;
- pp_show_color (&pp) = pp_show_color (global_dc->m_printer);
- bool first = true;
- for (auto iter : escaped_decls)
+ class escaped_list_element : public pp_element
+ {
+ public:
+ escaped_list_element (auto_vec<tree> &escaped_decls)
+ : m_escaped_decls (escaped_decls)
{
- if (first)
- first = false;
- else
- pp_string (&pp, ", ");
- pp_printf (&pp, "%qD", iter);
}
+
+ void add_to_phase_2 (pp_markup::context &ctxt) final override
+ {
+ /* We can't call pp_printf directly on ctxt.m_pp from within
+ formatting. As a workaround, work with a clone of the pp. */
+ std::unique_ptr<pretty_printer> pp (ctxt.m_pp.clone ());
+ bool first = true;
+ for (auto iter : m_escaped_decls)
+ {
+ if (first)
+ first = false;
+ else
+ pp_string (pp.get (), ", ");
+ pp_printf (pp.get (), "%qD", iter);
+ }
+ pp_string (&ctxt.m_pp, pp_formatted_text (pp.get ()));
+ }
+
+ private:
+ auto_vec<tree> &m_escaped_decls;
+ } e_escaped (escaped_decls);
+
/* Print the number to make it easier to write DejaGnu tests for
the "nothing has escaped" case. */
- warning_at (cd.get_location (), 0, "escaped: %i: %s",
+ warning_at (cd.get_location (), 0, "escaped: %i: %e",
escaped_decls.length (),
- pp_formatted_text (&pp));
+ &e_escaped);
}
};
#include "hash-set.h"
#include "diagnostic.h"
#include "pretty-print.h"
+#include "pretty-print-markup.h"
#include "tree-pretty-print.h"
#include "intl.h"
the "template" function declaration TMPL and DECL. The word "template"
doesn't necessarily refer to a C++ template but rather a declaration
whose attributes should be matched by those on DECL. For a non-zero
- return value set *ATTRSTR to a string representation of the list of
- mismatched attributes with quoted names.
+ return value append the names of the mismatcheed attributes to OUTATTRS.
ATTRLIST is a list of additional attributes that SPEC should be
taken to ultimately be declared with. */
unsigned
decls_mismatched_attributes (tree tmpl, tree decl, tree attrlist,
const char* const blacklist[],
- pretty_printer *attrstr)
+ auto_vec<const char *> &outattrs)
{
if (TREE_CODE (tmpl) != FUNCTION_DECL)
return 0;
if (!found)
{
- if (nattrs)
- pp_string (attrstr, ", ");
- pp_begin_quote (attrstr, pp_show_color (global_dc->m_printer));
- pp_string (attrstr, blacklist[i]);
- pp_end_quote (attrstr, pp_show_color (global_dc->m_printer));
+ outattrs.safe_push (blacklist[i]);
++nattrs;
}
"returns_twice", NULL
};
- pretty_printer attrnames;
if (warn_attribute_alias > 1)
{
/* With -Wattribute-alias=2 detect alias declarations that are more
restrictive than their targets first. Those indicate potential
codegen bugs. */
+ auto_vec<const char *> mismatches;
if (unsigned n = decls_mismatched_attributes (alias, target, NULL_TREE,
- blacklist, &attrnames))
+ blacklist, mismatches))
{
auto_diagnostic_group d;
+ pp_markup::comma_separated_quoted_strings e (mismatches);
if (warning_n (DECL_SOURCE_LOCATION (alias),
OPT_Wattribute_alias_, n,
"%qD specifies more restrictive attribute than "
- "its target %qD: %s",
+ "its target %qD: %e",
"%qD specifies more restrictive attributes than "
- "its target %qD: %s",
- alias, target, pp_formatted_text (&attrnames)))
+ "its target %qD: %e",
+ alias, target, &e))
inform (DECL_SOURCE_LOCATION (target),
"%qD target declared here", alias);
return;
/* Detect alias declarations that are less restrictive than their
targets. Those suggest potential optimization opportunities
(solved by adding the missing attribute(s) to the alias). */
+ auto_vec<const char *> mismatches;
if (unsigned n = decls_mismatched_attributes (target, alias, NULL_TREE,
- blacklist, &attrnames))
+ blacklist, mismatches))
{
auto_diagnostic_group d;
+ pp_markup::comma_separated_quoted_strings e (mismatches);
if (warning_n (DECL_SOURCE_LOCATION (alias),
OPT_Wmissing_attributes, n,
"%qD specifies less restrictive attribute than "
- "its target %qD: %s",
+ "its target %qD: %e",
"%qD specifies less restrictive attributes than "
- "its target %qD: %s",
- alias, target, pp_formatted_text (&attrnames)))
+ "its target %qD: %e",
+ alias, target, &e))
inform (DECL_SOURCE_LOCATION (target),
"%qD target declared here", alias);
}
extern unsigned decls_mismatched_attributes (tree, tree, tree,
const char* const[],
- pretty_printer*);
+ auto_vec<const char *> &);
extern void maybe_diag_alias_attributes (tree, tree);
#include "target.h"
#include "builtins.h"
#include "omp-general.h"
+#include "pretty-print-markup.h"
/* The type of functions taking a tree, and some additional data, and
returning an int. */
/* Put together a list of the black listed attributes that the primary
template is declared with that the specialization is not, in case
it's not apparent from the most recent declaration of the primary. */
- pretty_printer str;
+ auto_vec<const char *> mismatches;
unsigned nattrs = decls_mismatched_attributes (tmpl, spec, attrlist,
- blacklist, &str);
+ blacklist, mismatches);
if (!nattrs)
return;
if (warning_at (DECL_SOURCE_LOCATION (spec), OPT_Wmissing_attributes,
"explicit specialization %q#D may be missing attributes",
spec))
- inform (DECL_SOURCE_LOCATION (tmpl),
- nattrs > 1
- ? G_("missing primary template attributes %s")
- : G_("missing primary template attribute %s"),
- pp_formatted_text (&str));
+ {
+ pp_markup::comma_separated_quoted_strings e (mismatches);
+ inform (DECL_SOURCE_LOCATION (tmpl),
+ nattrs > 1
+ ? G_("missing primary template attributes %e")
+ : G_("missing primary template attribute %e"),
+ &e);
+ }
}
/* Check to see if the function just declared, as indicated in
#include "demangle.h"
#include "attr-fnspec.h"
#include "pointer-query.h"
+#include "pretty-print-markup.h"
/* Return true if tree node X has an associated location. */
return false;
/* Print a note with the valid memory models. */
- pretty_printer pp;
- pp_show_color (&pp) = pp_show_color (global_dc->m_printer);
+ auto_vec<const char *> strings;
for (unsigned i = 0; valid[i] != UCHAR_MAX; ++i)
{
const char *modname = memory_models[valid[i]].modname;
- pp_printf (&pp, "%s%qs", i ? ", " : "", modname);
+ strings.safe_push (modname);
}
-
- inform (loc, "valid models are %s", pp_formatted_text (&pp));
+ pp_markup::comma_separated_quoted_strings e (strings);
+ inform (loc, "valid models are %e", &e);
return true;
}
/* Print a note with the valid failure memory models which are
those with a value less than or equal to the success mode. */
- char buf[120];
- *buf = '\0';
+ auto_vec<const char *> strings;
for (unsigned i = 0;
memory_models[i].modval <= memmodel_base (sucs); ++i)
{
- if (*buf)
- strcat (buf, ", ");
-
const char *modname = memory_models[valid[i]].modname;
- sprintf (buf + strlen (buf), "'%s'", modname);
+ strings.safe_push (modname);
}
+ pp_markup::comma_separated_quoted_strings e (strings);
- inform (loc, "valid models are %s", buf);
+ inform (loc, "valid models are %e", &e);
return true;
}
DISABLE_COPY_AND_ASSIGN (element);
};
+/* Concrete subclass: handle "%e" by printing a comma-separated list
+ of quoted strings. */
+
+class comma_separated_quoted_strings : public element
+{
+public:
+ comma_separated_quoted_strings (const auto_vec<const char *> &strings)
+ : m_strings (strings)
+ {
+ }
+
+ void add_to_phase_2 (context &ctxt) final override;
+
+private:
+ const auto_vec<const char *> &m_strings;
+};
+
} // namespace pp_markup
#endif /* GCC_PRETTY_PRINT_MARKUP_H */
const char *)));
}
+void
+pp_markup::comma_separated_quoted_strings::add_to_phase_2 (context &ctxt)
+{
+ for (unsigned i = 0; i < m_strings.length (); i++)
+ {
+ if (i > 0)
+ pp_string (&ctxt.m_pp, ", ");
+ ctxt.begin_quote ();
+ pp_string (&ctxt.m_pp, m_strings[i]);
+ ctxt.end_quote ();
+ }
+}
+
/* Color names for expressing "expected" vs "actual" values. */
const char *const highlight_colors::expected = "highlight-a";
const char *const highlight_colors::actual = "highlight-b";
"In function: `test_fn'\nunexpected foo: 42 bar: `test'");
}
+/* Verify usage of pp_printf from within a pp_element's
+ add_to_phase_2 vfunc. */
+static void
+test_pp_printf_within_pp_element ()
+{
+ class kv_element : public pp_element
+ {
+ public:
+ kv_element (const char *key, int value)
+ : m_key (key), m_value (value)
+ {
+ }
+
+ void add_to_phase_2 (pp_markup::context &ctxt) final override
+ {
+ /* We can't call pp_printf directly on ctxt.m_pp from within
+ formatting. As a workaround, work with a clone of the pp. */
+ std::unique_ptr<pretty_printer> pp (ctxt.m_pp.clone ());
+ pp_printf (pp.get (), "(%qs: %qi)", m_key, m_value);
+ pp_string (&ctxt.m_pp, pp_formatted_text (pp.get ()));
+ }
+
+ private:
+ const char *m_key;
+ int m_value;
+ };
+
+ auto_fix_quotes fix_quotes;
+
+ kv_element e1 ("foo", 42);
+ kv_element e2 ("bar", 1066);
+ ASSERT_PP_FORMAT_2 ("before (`foo': `42') (`bar': `1066') after",
+ "before %e %e after",
+ &e1, &e2);
+ assert_pp_format_colored (SELFTEST_LOCATION,
+ ("before "
+ "(`\33[01m\33[Kfoo\33[m\33[K'"
+ ": "
+ "`\33[01m\33[K42\33[m\33[K')"
+ " "
+ "(`\33[01m\33[Kbar\33[m\33[K'"
+ ": "
+ "`\33[01m\33[K1066\33[m\33[K')"
+ " after"),
+ "before %e %e after",
+ &e1, &e2);
+}
+
/* A subclass of pretty_printer for use by test_prefixes_and_wrapping. */
class test_pretty_printer : public pretty_printer
}
+/* Verify that class comma_separated_quoted_strings works as expected. */
+
+static void
+test_comma_separated_quoted_strings ()
+{
+ auto_fix_quotes fix_quotes;
+
+ auto_vec<const char *> none;
+ pp_markup::comma_separated_quoted_strings e_none (none);
+
+ auto_vec<const char *> one;
+ one.safe_push ("one");
+ pp_markup::comma_separated_quoted_strings e_one (one);
+
+ auto_vec<const char *> many;
+ many.safe_push ("0");
+ many.safe_push ("1");
+ many.safe_push ("2");
+ pp_markup::comma_separated_quoted_strings e_many (many);
+
+ ASSERT_PP_FORMAT_3 ("none: () one: (`one') many: (`0', `1', `2')",
+ "none: (%e) one: (%e) many: (%e)",
+ &e_none, &e_one, &e_many);
+ assert_pp_format_colored (SELFTEST_LOCATION,
+ "one: (`\e[01m\e[Kone\e[m\e[K')",
+ "one: (%e)",
+ &e_one);
+}
+
/* Run all of the selftests within this file. */
void
test_custom_tokens_1 ();
test_custom_tokens_2 ();
test_pp_format_stack ();
+ test_pp_printf_within_pp_element ();
test_prefixes_and_wrapping ();
test_urls ();
test_urls_from_braces ();
test_null_urls ();
test_urlification ();
test_utf8 ();
+ test_comma_separated_quoted_strings ();
}
} // namespace selftest
__analyzer_dump_escaped (); /* { dg-warning "escaped: 0: " } */
unknown_fn (&local_1);
- __analyzer_dump_escaped (); /* { dg-warning "escaped: 1: 'local_1'" "" { target c } } */
- /* { dg-warning "escaped: 1: 'int local_1'" "" { target c++ } .-1 } */
+ __analyzer_dump_escaped (); /* { dg-warning "escaped: 1: 'local_1'" } */
/* Should be idempotent. */
unknown_fn (&local_1);
- __analyzer_dump_escaped (); /* { dg-warning "escaped: 1: 'local_1'" "" { target c } } */
- /* { dg-warning "escaped: 1: 'int local_1'" "" { target c++ } .-1 } */
+ __analyzer_dump_escaped (); /* { dg-warning "escaped: 1: 'local_1'" } */
/* Escape a static global. */
unknown_fn (&only_used_by_test_1);
- __analyzer_dump_escaped (); /* { dg-warning "escaped: 2: 'local_1', 'only_used_by_test_1'" "" { target c } } */
- /* { dg-warning "escaped: 2: 'int local_1', 'int only_used_by_test_1'" "" { target c++ } .-1 } */
+ __analyzer_dump_escaped (); /* { dg-warning "escaped: 2: 'local_1', 'only_used_by_test_1'" } */
}