From: Matthew Malcomson <mmalcom...@nvidia.com>

I've posted the patch on the relevant Bugzilla, but also sending to
mailing list.  If should have only done one please do mention.

----------------- 8< ----------- >8 ----------------
When making warnings trigger a failure in template substitution I
could not find any way to trigger the warning about builtin speculation
not being available on the given target.

Turns out I misread the code -- this warning happens when the
speculation_barrier pattern is not defined.

Here we add an effective target to represent
"__builtin_speculation_safe_value is available on this target" and use
that to adjust our test on SFINAE behaviour accordingly.
N.b. this means that we get extra testing -- not just that things work
on targets which support __builtin_speculation_safe_value, but also that
the behaviour works on targets which don't support it.

Tested with AArch64 native, AArch64 cross compiler, and RISC-V cross
compiler (just running the tests that I've changed).

Points of interest for any reviewer:

In the new `check_known_compiler_messages_nocache` procedure I use some
procedures from `prune.exp`.  This works for the use I need in
the g++ testsuite since g++.exp imports prune.exp and g++-dg.exp
includes gcc-dg.exp which does the initialisation of prune_notes
(needed for this procedure).
- Would it be preferred to include a `load_lib prune.exp` statement at
  the top of `target-supports.exp` in order to use this procedure?
- What about the handling of `initialize_prune_notes` which must have
  been called before calling `prune_gcc_output`?
- I believe it's sensible to not use `gcc-dg-prune` which wraps
  `prune_gcc_output` since I don't believe the wrapping functionality
  useful here -- wanted to highlight that decision for review.

Ok for trunk?

gcc/testsuite/ChangeLog:

        PR/117991
        * g++.dg/template/builtin-speculation-overloads.def: SUCCESS
        argument in SPECULATION_ASSERTS now uses a macro `true_def`
        instead of the literal `true` for arguments which should work
        with `__builtin_speculation_safe_value`.
        * g++.dg/template/builtin-speculation-overloads1.C: Define
        `true_def` macro on command line to compiler according to the
        effective target representing that
        `__builtin_speculation_safe_value` does something on this
        target.
        * g++.dg/template/builtin-speculation-overloads4.C: Likewise.
        * lib/target-supports.exp
        (check_known_compiler_messages_nocache): New.
        (check_effective_target_speculation_barrier_defined): New.

Signed-off-by: Matthew Malcomson <mmalcom...@nvidia.com>
---
 .../builtin-speculation-overloads.def         |  9 ++-
 .../template/builtin-speculation-overloads1.C |  2 +
 .../template/builtin-speculation-overloads4.C |  2 +
 gcc/testsuite/lib/target-supports.exp         | 62 +++++++++++++++++++
 4 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/gcc/testsuite/g++.dg/template/builtin-speculation-overloads.def 
b/gcc/testsuite/g++.dg/template/builtin-speculation-overloads.def
index 39d9b748d52..ada13e6f77c 100644
--- a/gcc/testsuite/g++.dg/template/builtin-speculation-overloads.def
+++ b/gcc/testsuite/g++.dg/template/builtin-speculation-overloads.def
@@ -15,14 +15,17 @@ class X{};
 class Large { public: int arr[10]; };
 class Incomplete;
 
+/* Using `true_def` in order to account for the fact that if this target
+ * doesn't support __builtin_speculation_safe_value at all everything fails to
+ * substitute.  */
 #define SPECULATION_ASSERTS                                                    
\
-  MAKE_SPECULATION_ASSERT (int, true)                                          
\
+  MAKE_SPECULATION_ASSERT (int, true_def)                                      
\
   MAKE_SPECULATION_ASSERT (float, false)                                       
\
   MAKE_SPECULATION_ASSERT (X, false)                                           
\
   MAKE_SPECULATION_ASSERT (Large, false)                                       
\
   MAKE_SPECULATION_ASSERT (Incomplete, false)                                  
\
-  MAKE_SPECULATION_ASSERT (int *, true)                                        
\
-  MAKE_SPECULATION_ASSERT (long, true)
+  MAKE_SPECULATION_ASSERT (int *, true_def)                                    
\
+  MAKE_SPECULATION_ASSERT (long, true_def)
 
 int main() {
     SPECULATION_ASSERTS
diff --git a/gcc/testsuite/g++.dg/template/builtin-speculation-overloads1.C 
b/gcc/testsuite/g++.dg/template/builtin-speculation-overloads1.C
index bc8f1083a99..4c50d4aa6f5 100644
--- a/gcc/testsuite/g++.dg/template/builtin-speculation-overloads1.C
+++ b/gcc/testsuite/g++.dg/template/builtin-speculation-overloads1.C
@@ -1,5 +1,7 @@
 /* Check that overloaded builtins can be used in templates with SFINAE.  */
 // { dg-do compile { target c++17 } }
+// { dg-additional-options "-Dtrue_def=true" { target 
speculation_barrier_defined } }
+// { dg-additional-options "-Dtrue_def=false" { target { ! 
speculation_barrier_defined } } }
 
 /* Checks performed here:
    Various types (some that work, some that don't).  */
diff --git a/gcc/testsuite/g++.dg/template/builtin-speculation-overloads4.C 
b/gcc/testsuite/g++.dg/template/builtin-speculation-overloads4.C
index c024a21fa18..cc0b3131af7 100644
--- a/gcc/testsuite/g++.dg/template/builtin-speculation-overloads4.C
+++ b/gcc/testsuite/g++.dg/template/builtin-speculation-overloads4.C
@@ -1,5 +1,7 @@
 /* Check that overloaded builtins can be used in templates with SFINAE.  */
 // { dg-do compile { target c++17 } }
+// { dg-additional-options "-Dtrue_def=true" { target 
speculation_barrier_defined } }
+// { dg-additional-options "-Dtrue_def=false" { target { ! 
speculation_barrier_defined } } }
 
 /* Checks performed here:
    Optional parameter missing works same as with optional parameter specified. 
 */
diff --git a/gcc/testsuite/lib/target-supports.exp 
b/gcc/testsuite/lib/target-supports.exp
index ff95b88f3c4..b8a667d9187 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -180,8 +180,51 @@ proc clear_effective_target_cache { } {
     array unset et_cache
 }
 
+# Like check_no_compiler_messages_nocache, but returns true if the compiler
+# printed a known set of messages.  `messages` is a list of messages to expect
+# *after* pruning with `prune_gcc_output` and removing empty lines.  Each entry
+# in the list should be a regexp pattern matching each line of the output in
+# turn.
+proc check_known_compiler_messages_nocache { messages args } {
+    verbose "Arguments: $args" 3
+    verbose "messages: \"$messages\"" 3
+    initialize_prune_notes
+    set result [eval check_compile $args]
+    set tool_output [lindex $result 0]
+    set output_file [lindex $result 1]
+    remote_file build delete $output_file
+    verbose "pruning output of: \"$tool_output\"" 3
+    set tool_output [prune_gcc_output $tool_output]
+    set lines [split $tool_output "\n"]
+    # Remove empty lines to make interface to this procedure nice.
+    verbose "Comparing \"$lines\" against \"$messages\"" 3
+    set lines [lmap value $lines {
+       if { ! [string match "" $value] } {
+           string cat $value
+       } else {
+           continue
+       }}]
+    verbose "After removing empty lines \"$lines\" against \"$messages\"" 3
+    if { [llength $lines] != [llength $messages] } {
+       verbose "message lengths different" 3
+       return 0
+    }
+    verbose "message lengths same" 3
+    foreach msg $messages line $lines {
+       verbose "Comparing \"$msg\" against \"$line\"" 3
+       if { ! [regexp $msg $line] } {
+           verbose "line did not compare equal" 3
+           return 0
+       }
+    }
+    verbose "message values same" 3
+    return 1
+}
+
 # Like check_compile, but delete the output file and return true if the
 # compiler printed no messages.
+# Do not implement in terms of `check_known_compiler_messages_nocach` since
+# that procedure includes pruning of messages.
 proc check_no_compiler_messages_nocache {args} {
     set result [eval check_compile $args]
     set lines [lindex $result 0]
@@ -14304,3 +14347,22 @@ proc check_effective_target_alarm { } {
        }
     }]
 }
+
+# Return true if a speculation barrier is defined on the target.
+proc check_effective_target_speculation_barrier_defined { } {
+    # N.b. not using the existing abstractions around `gcc_warning_prefix`
+    # since that's set depending on the tool that's getting tested while this
+    # effective target is used for all tools.  Moreover this effective target
+    # is always compiling C while different tools are often testing different
+    # languages.  Hence we always know the warning prefix that would be used
+    # for this test.
+    return [check_cached_effective_target speculation_barrier_defined {
+       expr ! [check_known_compiler_messages_nocache \
+           [list "warning: this target does not define a speculation 
barrier.*"] \
+           specbar assembly {
+               int main (int argc, char **argv) { 
+                   return __builtin_speculation_safe_value (argc);
+               }
+           }]
+    }]
+}
-- 
2.43.0

Reply via email to