The 08/28/2025 14:43, Jason Merrill wrote: > On 8/28/25 5:49 AM, alfie.richa...@arm.com wrote: > > From: Alfie Richards <alfie.richa...@arm.com> > > > > Adds the target_version and target_clones attributes to diagnostic messages > > for target_version semantics. > > > > This is because the target_version/target_clones attributes affect the > > identity > > of the decls, so need to be represented in diagnostics for them. > > > > This also requires making maybe_print_whitespace available to c++ code so > > pp_c_maybe_whitespace > > But why do we need to call it in C++ when we don't in C?
(Resending as I forgot to reply all) Because I use it to print the white space after the attribute which isn't needed in the C diagnostic. The difficulty is I want C++ to do: 'float foo [[target_version("sve")]] ()' (with a space before and after) and 'float foo()' with no spaces (unchanged from current formatting) But for C I want: 'foo [[target_version("sve")]]' Notably, without a space after the attribute. The slightly ugly way I achieved this is that pp_c_function_target_version sets pp->set_padding (pp_before) if it prints the attribute, so then pp_cpp_maybe_whitespace can be used only in the C++ code to add the extra white space only if the attribute is added. I'm not happy with this way of achieving this, if you know a simpler way to achieve this I would be happy to change it. > > > we can control if whitespace is needed cosistantly between c and c++ > > "consistently" > > > diagnostics. > > > > After this change diagnostics look like: > > > > c: > > ``` > > test.c:6:8: error: redefinition of ‘foo [[target_version("sve")]]’ > > 6 | float foo () {return 1;} > > | ^~~ > > test.c:3:8: note: previous definition of ‘foo [[target_version("sve")]]’ > > with type ‘float(void)’ > > 3 | float foo () {return 2;} > > | ^~~ > > test.c:12:8: error: redefinition of ‘bar [[target_clones("sve")]]’ > > 12 | float bar () {return 1;} > > | ^~~ > > test.c:9:8: note: previous definition of ‘bar [[target_clones("sve")]]’ > > with type ‘float(void)’ > > 9 | float bar () {return 2;} > > | ^~~ > > ``` > > > > c++: > > ``` > > test.cpp:6:8: error: redefinition of ‘float foo [[target_version("sve")]] > > ()’ > > 6 | float foo () {return 1;} > > | ^~~ > > test.cpp:3:8: note: ‘float foo [[target_version("sve")]] ()’ previously > > defined here > > 3 | float foo () {return 2;} > > | ^~~ > > test.cpp:12:8: error: redefinition of ‘float bar [[target_clones("sve")]] > > ()’ > > 12 | float bar () {return 1;} > > | ^~~ > > test.cpp:9:8: note: ‘float bar [[target_clones("sve")]] ()’ previously > > defined here > > 9 | float bar () {return 2;} > > | ^~~ > > ``` > > > > This only affects targets which use target_version (aarch64 and riscv). > > > > gcc/c-family/ChangeLog: > > > > * c-pretty-print.cc (pp_c_function_target_version): New function. > > (pp_c_function_target_clones): New function. > > (pp_c_maybe_whitespace): Move to c-pretty-print.h. > > * c-pretty-print.h (pp_c_function_target_version): New function. > > (pp_c_function_target_clones): New function. > > (pp_c_maybe_whitespace): Moved here from c-pretty-print.cc. > > > > gcc/c/ChangeLog: > > > > * c-objc-common.cc (c_tree_printer): Add printing of target_clone and > > target_version in decl diagnostics. > > > > gcc/cp/ChangeLog: > > > > * cxx-pretty-print.h (pp_cxx_function_target_version): New macro. > > (pp_cxx_function_target_clones): Ditto. > > (pp_cxx_maybe_whitespace): Ditto. > > * error.cc (dump_function_decl): Add printing of target_clone and > > target_version in decl diagnostics. > > --- > > gcc/c-family/c-pretty-print.cc | 77 +++++++++++++++++++++++++++++++--- > > gcc/c-family/c-pretty-print.h | 8 ++++ > > gcc/c/c-objc-common.cc | 6 +++ > > gcc/cp/cxx-pretty-print.h | 5 +++ > > gcc/cp/error.cc | 8 ++++ > > 5 files changed, 98 insertions(+), 6 deletions(-) > > > > diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc > > index fad6b5eb9b0..5adb13b9784 100644 > > --- a/gcc/c-family/c-pretty-print.cc > > +++ b/gcc/c-family/c-pretty-print.cc > > @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see > > #include "function.h" > > #include "basic-block.h" > > #include "gimple.h" > > +#include "tm.h" > > /* The pretty-printer code is primarily designed to closely follow > > (GNU) C and C++ grammars. That is to be contrasted with spaghetti > > @@ -45,12 +46,6 @@ along with GCC; see the file COPYING3. If not see > > takes expression or declaration contexts into account. */ > > -#define pp_c_maybe_whitespace(PP) \ > > - do { \ > > - if ((PP)->get_padding () == pp_before) \ > > - pp_c_whitespace (PP); \ > > - } while (0) > > - > > /* literal */ > > static void pp_c_char (c_pretty_printer *, int); > > @@ -3054,6 +3049,76 @@ pp_c_tree_decl_identifier (c_pretty_printer *pp, > > tree t) > > pp_c_identifier (pp, name); > > } > > +/* Prints "[version: VERSION]" for a versioned function decl. > > + This will only print for targets with target_version semantics. */ > > +void > > +pp_c_function_target_version (c_pretty_printer *pp, tree t) > > +{ > > + if (TARGET_HAS_FMV_TARGET_ATTRIBUTE) > > + return; > > + > > + string_slice version = get_target_version (t); > > + if (!version.is_valid ()) > > + return; > > + > > + pp_c_whitespace (pp); > > + > > + pp_c_left_bracket (pp); > > + pp_c_left_bracket (pp); > > + pp_string (pp, "target_version"); > > + pp_c_left_paren (pp); > > + pp_doublequote (pp); > > + pp_string_n (pp, version.begin (), version.size ()); > > + pp_doublequote (pp); > > + pp_c_right_paren (pp); > > + pp_c_right_bracket (pp); > > + pp_c_right_bracket (pp); > > + > > + pp->set_padding (pp_before); > > +} > > + > > +/* Prints "[clones: VERSION, +]" for a versioned function decl. > > + This only works for targets with target_version semantics. */ > > +void > > +pp_c_function_target_clones (c_pretty_printer *pp, tree t) > > +{ > > + /* Only print for target_version semantics. > > + This is because for target FMV semantics a target_clone always defines > > + the entire FMV set. target_version semantics can mix target_clone and > > + target_version decls in the definition of a FMV set and so the > > + target_clone becomes a part of the identity of the declaration. */ > > + if (TARGET_HAS_FMV_TARGET_ATTRIBUTE) > > + return; > > + > > + auto_vec<string_slice> versions = get_clone_versions (t, NULL, false); > > + if (versions.is_empty ()) > > + return; > > + > > + pp_c_whitespace (pp); > > + > > + string_slice final_version = versions.pop (); > > + pp_c_left_bracket (pp); > > + pp_c_left_bracket (pp); > > + pp_string (pp, "target_clones"); > > + pp_c_left_paren (pp); > > + for (string_slice version : versions) > > + { > > + pp_doublequote (pp); > > + pp_string_n (pp, version.begin (), version.size ()); > > + pp_doublequote (pp); > > + pp_string (pp, ","); > > + pp_c_whitespace (pp); > > + } > > + pp_doublequote (pp); > > + pp_string_n (pp, final_version.begin (), final_version.size ()); > > + pp_doublequote (pp); > > + pp_c_right_paren (pp); > > + pp_c_right_bracket (pp); > > + pp_c_right_bracket (pp); > > + > > + pp->set_padding (pp_before); > > +} > > + > > #if CHECKING_P > > namespace selftest { > > diff --git a/gcc/c-family/c-pretty-print.h b/gcc/c-family/c-pretty-print.h > > index c8fb6789991..5e00b952c81 100644 > > --- a/gcc/c-family/c-pretty-print.h > > +++ b/gcc/c-family/c-pretty-print.h > > @@ -102,6 +102,12 @@ public: > > #define pp_ptr_operator(PP, D) (PP)->ptr_operator (PP, D) > > #define pp_parameter_list(PP, T) (PP)->parameter_list (PP, T) > > +#define pp_c_maybe_whitespace(PP) \ > > + do { \ > > + if ((PP)->get_padding () == pp_before) \ > > + pp_c_whitespace (PP); \ > > + } while (0) > > + > > void pp_c_whitespace (c_pretty_printer *); > > void pp_c_left_paren (c_pretty_printer *); > > void pp_c_right_paren (c_pretty_printer *); > > @@ -138,6 +144,8 @@ void pp_c_ws_string (c_pretty_printer *, const char *); > > void pp_c_identifier (c_pretty_printer *, const char *); > > void pp_c_string_literal (c_pretty_printer *, tree); > > void pp_c_integer_constant (c_pretty_printer *, tree); > > +void pp_c_function_target_version (c_pretty_printer *, tree); > > +void pp_c_function_target_clones (c_pretty_printer *, tree); > > void print_c_tree (FILE *file, tree t, dump_flags_t); > > diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc > > index 5c50983544d..109a8cb33ee 100644 > > --- a/gcc/c/c-objc-common.cc > > +++ b/gcc/c/c-objc-common.cc > > @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see > > #include "c-tree.h" > > #include "intl.h" > > #include "c-family/c-pretty-print.h" > > +#include "tree-core.h" > > #include "tree-pretty-print.h" > > #include "tree-pretty-print-markup.h" > > #include "gimple-pretty-print.h" > > @@ -359,6 +360,11 @@ c_tree_printer (pretty_printer *pp, text_info *text, > > const char *spec, > > if (DECL_NAME (t)) > > { > > pp_identifier (cpp, lang_hooks.decl_printable_name (t, 2)); > > + if (TREE_CODE (t) == FUNCTION_DECL) > > + { > > + pp_c_function_target_version (cpp, t); > > + pp_c_function_target_clones (cpp, t); > > + } > > return true; > > } > > break; > > diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h > > index 86e0ce7d85f..356fd6e4d23 100644 > > --- a/gcc/cp/cxx-pretty-print.h > > +++ b/gcc/cp/cxx-pretty-print.h > > @@ -81,8 +81,13 @@ public: > > #define pp_cxx_ws_string(PP, I) pp_c_ws_string (PP, I) > > #define pp_cxx_identifier(PP, I) pp_c_identifier (PP, I) > > +#define pp_cxx_maybe_whitespace(PP) pp_c_maybe_whitespace (PP) > > #define pp_cxx_tree_identifier(PP, T) \ > > pp_c_tree_identifier (PP, T) > > +#define pp_cxx_function_target_version(PP, T) \ > > + pp_c_function_target_version (PP, T) > > +#define pp_cxx_function_target_clones(PP, T) \ > > + pp_c_function_target_clones (PP, T) > > void pp_cxx_begin_template_argument_list (cxx_pretty_printer *); > > void pp_cxx_end_template_argument_list (cxx_pretty_printer *); > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc > > index 8ef9f9ee458..16dfeafc07a 100644 > > --- a/gcc/cp/error.cc > > +++ b/gcc/cp/error.cc > > @@ -2008,6 +2008,14 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, > > int flags) > > dump_function_name (pp, t, dump_function_name_flags); > > + /* By default we need no padding here, but if we emit target_version or > > + target_clones then we need some. */ > > + pp->set_padding (pp_none); > > + pp_cxx_function_target_version (pp, t); > > + pp_cxx_maybe_whitespace (pp); > > + pp_cxx_function_target_clones (pp, t); > > + pp_cxx_maybe_whitespace (pp); > > + > > if (!(flags & TFF_NO_FUNCTION_ARGUMENTS)) > > { > > int const parm_flags > -- Alfie Richards