The LTO testsuite lacked support for testing expected link-time errors and
examining assembly output from the ltrans phase. This made it difficult to
write tests for LTO features that detect conflicts at link time or need to
verify code generation in specific LTRANS units.
This patch adds two capabilities to the LTO testsuite:
The dg-lto-error directive allows tests to specify expected link-time errors.
When present, lto.exp expects the link to fail and marks the test as PASS if it
fails with matching diagnostics, or FAIL if the link unexpectedly succeeds.
This parallels the existing dg-lto-warning and dg-lto-message directives.
The new scan-ltrans-assembler procedures provide a way to examine the assembly
output (.ltrans*.s files) generated during the ltrans phase. The
scan-ltrans-assembler procedure checks for pattern presence, while
scan-ltrans-assembler-times verifies exact occurrence counts.
Future patches will make use of this support for link-time diagnostics and
ltrans code generation testing.
gcc/testsuite/ChangeLog:
* lib/lto.exp (lto-link-and-maybe-run): Add dg_lto_has_error
handling to expect link failures when dg-lto-error is present.
Pass test when link fails as expected, fail when link succeeds
despite errors.
(lto-can-handle-directive): Add dg-lto-error to recognized
directive list.
(lto-execute-1): Initialize dg_lto_has_error flag.
* lib/scanltrans.exp (scan-ltrans-assembler): New procedure to
scan for patterns in .ltrans*.s assembly files.
(scan-ltrans-assembler-times): New procedure to verify pattern
count across all ltrans assembly files.
* g++.dg/lto/scan-ltrans-asm-1_0.C: New test.
* g++.dg/lto/scan-ltrans-asm-1_1.C: New test.
* gcc.dg/lto/dg-lto-error-1_0.c: New test.
* gcc.dg/lto/dg-lto-error-1_1.c: New test.
* gcc.dg/lto/dg-lto-error-2_0.c: New test.
* gcc.dg/lto/dg-lto-error-2_1.c: New test.
* gcc.dg/lto/scan-ltrans-asm-1_0.c: New test.
* gcc.dg/lto/scan-ltrans-asm-1_1.c: New test.
Signed-off-by: Luis Silva <[email protected]>
---
gcc/testsuite/g++.dg/lto/lto.exp | 1 +
.../g++.dg/lto/scan-ltrans-asm-1_0.C | 18 ++++
.../g++.dg/lto/scan-ltrans-asm-1_1.C | 5 +
gcc/testsuite/gcc.dg/lto/dg-lto-error-1_0.c | 11 ++
gcc/testsuite/gcc.dg/lto/dg-lto-error-1_1.c | 3 +
gcc/testsuite/gcc.dg/lto/dg-lto-error-2_0.c | 10 ++
gcc/testsuite/gcc.dg/lto/dg-lto-error-2_1.c | 1 +
gcc/testsuite/gcc.dg/lto/lto.exp | 1 +
.../gcc.dg/lto/scan-ltrans-asm-1_0.c | 19 ++++
.../gcc.dg/lto/scan-ltrans-asm-1_1.c | 5 +
gcc/testsuite/lib/lto.exp | 92 ++++++++++++++++
gcc/testsuite/lib/scanltrans.exp | 100 ++++++++++++++++++
12 files changed, 266 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/lto/scan-ltrans-asm-1_0.C
create mode 100644 gcc/testsuite/g++.dg/lto/scan-ltrans-asm-1_1.C
create mode 100644 gcc/testsuite/gcc.dg/lto/dg-lto-error-1_0.c
create mode 100644 gcc/testsuite/gcc.dg/lto/dg-lto-error-1_1.c
create mode 100644 gcc/testsuite/gcc.dg/lto/dg-lto-error-2_0.c
create mode 100644 gcc/testsuite/gcc.dg/lto/dg-lto-error-2_1.c
create mode 100644 gcc/testsuite/gcc.dg/lto/scan-ltrans-asm-1_0.c
create mode 100644 gcc/testsuite/gcc.dg/lto/scan-ltrans-asm-1_1.c
diff --git a/gcc/testsuite/g++.dg/lto/lto.exp b/gcc/testsuite/g++.dg/lto/lto.exp
index aca8e541bce..9b4c87d9f3d 100644
--- a/gcc/testsuite/g++.dg/lto/lto.exp
+++ b/gcc/testsuite/g++.dg/lto/lto.exp
@@ -34,6 +34,7 @@ load_lib target-libpath.exp
# Load the language-independent compabibility support procedures.
load_lib lto.exp
+load_lib scanltrans.exp
# If LTO has not been enabled, bail.
if { ![check_effective_target_lto] } {
diff --git a/gcc/testsuite/g++.dg/lto/scan-ltrans-asm-1_0.C
b/gcc/testsuite/g++.dg/lto/scan-ltrans-asm-1_0.C
new file mode 100644
index 00000000000..4502d1aafde
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/scan-ltrans-asm-1_0.C
@@ -0,0 +1,18 @@
+// { dg-lto-do link }
+// { dg-require-linker-plugin "" }
+// { dg-lto-options {{-O2 -flto -save-temps}} }
+
+int bar (int x);
+
+int foo (int a)
+{
+ return a * 2 + bar (a);
+}
+
+int
+main (void)
+{
+ return foo (42);
+}
+
+// { dg-final { scan-ltrans-assembler "main" } }
diff --git a/gcc/testsuite/g++.dg/lto/scan-ltrans-asm-1_1.C
b/gcc/testsuite/g++.dg/lto/scan-ltrans-asm-1_1.C
new file mode 100644
index 00000000000..41d47cc71f6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/scan-ltrans-asm-1_1.C
@@ -0,0 +1,5 @@
+int
+bar (int x)
+{
+ return x + 1;
+}
diff --git a/gcc/testsuite/gcc.dg/lto/dg-lto-error-1_0.c
b/gcc/testsuite/gcc.dg/lto/dg-lto-error-1_0.c
new file mode 100644
index 00000000000..677373ca1d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/dg-lto-error-1_0.c
@@ -0,0 +1,11 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options { { -O2 -flto } } } */
+
+extern void specific_function (void); /* { dg-lto-error "undefined reference
to .?specific_function" } */
+
+int
+main (void)
+{
+ specific_function ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/lto/dg-lto-error-1_1.c
b/gcc/testsuite/gcc.dg/lto/dg-lto-error-1_1.c
new file mode 100644
index 00000000000..ab94b97fdac
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/dg-lto-error-1_1.c
@@ -0,0 +1,3 @@
+void other_function (void)
+{
+}
diff --git a/gcc/testsuite/gcc.dg/lto/dg-lto-error-2_0.c
b/gcc/testsuite/gcc.dg/lto/dg-lto-error-2_0.c
new file mode 100644
index 00000000000..aa1e56c3d9c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/dg-lto-error-2_0.c
@@ -0,0 +1,10 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options { { -O2 -flto -fno-common } } } */
+
+int global_var = 100; /* { dg-lto-error "multiple definition of .?global_var"
} */
+
+int
+main (void)
+{
+ return global_var;
+}
diff --git a/gcc/testsuite/gcc.dg/lto/dg-lto-error-2_1.c
b/gcc/testsuite/gcc.dg/lto/dg-lto-error-2_1.c
new file mode 100644
index 00000000000..d5147b7b1a0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/dg-lto-error-2_1.c
@@ -0,0 +1 @@
+int global_var = 200;
diff --git a/gcc/testsuite/gcc.dg/lto/lto.exp b/gcc/testsuite/gcc.dg/lto/lto.exp
index 567eafda22d..674e4456919 100644
--- a/gcc/testsuite/gcc.dg/lto/lto.exp
+++ b/gcc/testsuite/gcc.dg/lto/lto.exp
@@ -33,6 +33,7 @@ load_lib gcc.exp
# Load the language-independent compabibility support procedures.
load_lib lto.exp
+load_lib scanltrans.exp
# If LTO has not been enabled, bail.
if { ![check_effective_target_lto] } {
diff --git a/gcc/testsuite/gcc.dg/lto/scan-ltrans-asm-1_0.c
b/gcc/testsuite/gcc.dg/lto/scan-ltrans-asm-1_0.c
new file mode 100644
index 00000000000..a8bef30c710
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/scan-ltrans-asm-1_0.c
@@ -0,0 +1,19 @@
+/* { dg-lto-do link } */
+/* { dg-require-linker-plugin "" } */
+/* { dg-lto-options { { -O2 -flto -save-temps } } } */
+
+int bar (int x);
+
+int
+foo (int a)
+{
+ return a * 2 + bar (a);
+}
+
+int
+main (void)
+{
+ return foo (42);
+}
+
+/* { dg-final { scan-ltrans-assembler "main" } } */
diff --git a/gcc/testsuite/gcc.dg/lto/scan-ltrans-asm-1_1.c
b/gcc/testsuite/gcc.dg/lto/scan-ltrans-asm-1_1.c
new file mode 100644
index 00000000000..41d47cc71f6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/scan-ltrans-asm-1_1.c
@@ -0,0 +1,5 @@
+int
+bar (int x)
+{
+ return x + 1;
+}
diff --git a/gcc/testsuite/lib/lto.exp b/gcc/testsuite/lib/lto.exp
index 64b7d992272..fdaecf4decf 100644
--- a/gcc/testsuite/lib/lto.exp
+++ b/gcc/testsuite/lib/lto.exp
@@ -372,6 +372,7 @@ proc lto-link-and-maybe-run { testname objlist dest optall
optfile optstr } {
global tool
global compile_type
global board_info
+ global dg_lto_has_error
upvar dg-messages-by-file dg-messages-by-file
@@ -419,6 +420,54 @@ proc lto-link-and-maybe-run { testname objlist dest optall
optfile optstr } {
# Prune unimportant visibility warnings before checking output.
set comp_output [lto_prune_warns $comp_output]
+ # Handle dg-lto-error: expect link failure and check pattern if specified.
+ if { [info exists dg_lto_has_error] && $dg_lto_has_error } {
+ verbose "lto.exp: dg-lto-error present, expecting link failure" 2
+ set link_failed [expr {![file_on_host exists $dest] || $comp_output !=
""}]
+
+ global dg_lto_error_line
+ global dg_lto_error_comment
+ global dg-linenum-format
+ set at_line ""
+ set comment_str ""
+
+ if { [info exists dg_lto_error_comment] && $dg_lto_error_comment != ""
} {
+ set comment_str " $dg_lto_error_comment"
+ }
+
+ if { [info exists dg_lto_error_line] && $dg_lto_error_line != "" } {
+ # $line will either be a formatted line number or a number all by
+ # itself. Delete the formatting.
+ set line $dg_lto_error_line
+ scan $line ${dg-linenum-format} line
+ set at_line " at line $line"
+ }
+
+ set describe_where "$comment_str$at_line (test for LTO link errors)"
+
+ if { $link_failed } {
+ global dg_lto_error_pattern
+ if { [info exists dg_lto_error_pattern] && $dg_lto_error_pattern !=
"" } {
+ if { [regexp -- $dg_lto_error_pattern $comp_output] } {
+ verbose "lto.exp: link failed with expected pattern" 2
+ pass "$testcase $testname link $optstr$describe_where"
+ } else {
+ verbose "lto.exp: pattern '$dg_lto_error_pattern' not found
in: $comp_output" 2
+ fail "$testcase $testname link $optstr$describe_where
(pattern not found)"
+ }
+ } else {
+ verbose "lto.exp: link failed as expected" 2
+ pass "$testcase $testname link $optstr$describe_where"
+ }
+ } else {
+ fail "$testcase $testname link $optstr$describe_where (expected
failure)"
+ }
+ if { ![string compare "execute" $compile_type] } {
+ unresolved "$testcase $testname execute $optstr"
+ }
+ return
+ }
+
if ![${tool}_check_compile "$testcase $testname link" $optstr \
$dest $comp_output] then {
if { ![string compare "execute" $compile_type] } {
@@ -453,6 +502,35 @@ proc lto-can-handle-directive { op } {
# dg-warning and dg-message append to dg-messages.
upvar dg-messages dg-messages
+ global dg_lto_has_error
+
+ # Handle dg-lto-error: linker errors lack source line info, so check
+ # for link failure and match error patterns against linker output.
+ if { $cmd == "dg-lto-error" } {
+ set dg_lto_has_error 1
+ verbose "lto.exp: dg-lto-error detected" 2
+
+ # Store the line number for reporting
+ global dg_lto_error_line
+ set dg_lto_error_line [lindex $op 1]
+ verbose "lto.exp: dg-lto-error line: '$dg_lto_error_line'" 2
+
+ # Store the comment/description if present
+ global dg_lto_error_comment
+ if { [llength $op] > 3 } {
+ set dg_lto_error_comment [lindex $op 3]
+ } else {
+ set dg_lto_error_comment ""
+ }
+ verbose "lto.exp: dg-lto-error comment: '$dg_lto_error_comment'" 2
+
+ if { [llength $op] > 2 } {
+ global dg_lto_error_pattern
+ set dg_lto_error_pattern [lindex $op 2]
+ verbose "lto.exp: dg-lto-error pattern: '$dg_lto_error_pattern'" 2
+ }
+ return 1
+ }
# A list of directives to recognize, and a list of directives
# to remap them to.
@@ -681,6 +759,10 @@ proc lto-execute-1 { src1 sid } {
global LTO_OPTIONS
global dg-final-code
global testname_with_flags
+ global dg_lto_has_error
+ global dg_lto_error_pattern
+ global dg_lto_error_line
+ global dg_lto_error_comment
# Get extra flags for this test from the primary source file, and
# process other dg-* options that this suite supports. Warn about
@@ -689,6 +771,16 @@ proc lto-execute-1 { src1 sid } {
set compile_type "run"
set dg-do-what [list ${dg-do-what-default} "" P]
array set dg-messages-by-file [list]
+ set dg_lto_has_error 0
+ if { [info exists dg_lto_error_pattern] } {
+ unset dg_lto_error_pattern
+ }
+ if { [info exists dg_lto_error_line] } {
+ unset dg_lto_error_line
+ }
+ if { [info exists dg_lto_error_comment] } {
+ unset dg_lto_error_comment
+ }
set extra_flags(0) [lto-get-options-main $src1]
set compile_xfail(0) ""
diff --git a/gcc/testsuite/lib/scanltrans.exp b/gcc/testsuite/lib/scanltrans.exp
index 4edaf6d9926..1ca63df5da7 100644
--- a/gcc/testsuite/lib/scanltrans.exp
+++ b/gcc/testsuite/lib/scanltrans.exp
@@ -78,3 +78,103 @@ foreach ir { tree rtl } {
}
}]
}
+
+# Scan LTRANS assembly output (.ltrans*.s files).
+
+proc scan-ltrans-assembler { args } {
+ if { [llength $args] < 1 } {
+ error "scan-ltrans-assembler: too few arguments"
+ return
+ }
+ if { [llength $args] > 2 } {
+ error "scan-ltrans-assembler: too many arguments"
+ return
+ }
+ if { [llength $args] >= 2 } {
+ switch [dg-process-target [lindex $args 1]] {
+ "S" { }
+ "N" { return }
+ "F" { setup_xfail "*-*-*" }
+ "P" { }
+ }
+ }
+
+ set testcase [testname-for-summary]
+ set pattern [lindex $args 0]
+ set pp_pattern [make_pattern_printable $pattern]
+ set testname [lindex $testcase 0]
+ set basename [file rootname $testname]
+ set output_files [dg_glob_remote "${basename}.ltrans*.s"]
+
+ if { $output_files == "" } {
+ verbose -log "$testcase: no ${basename}.ltrans*.s files found"
+ unresolved "$testcase scan-ltrans-assembler $pp_pattern"
+ return
+ }
+
+ set total_matches 0
+ foreach file $output_files {
+ set fd [open $file r]
+ set text [read $fd]
+ close $fd
+ set matches [regexp -all -- $pattern $text]
+ set total_matches [expr $total_matches + $matches]
+ }
+
+ if { $total_matches > 0 } {
+ pass "$testcase scan-ltrans-assembler $pp_pattern"
+ } else {
+ fail "$testcase scan-ltrans-assembler $pp_pattern"
+ }
+}
+set_required_options_for scan-ltrans-assembler
+
+proc scan-ltrans-assembler-times { args } {
+ if { [llength $args] < 2 } {
+ error "scan-ltrans-assembler-times: too few arguments"
+ return
+ }
+ if { [llength $args] > 3 } {
+ error "scan-ltrans-assembler-times: too many arguments"
+ return
+ }
+ if { [llength $args] >= 3 } {
+ switch [dg-process-target [lindex $args 2]] {
+ "S" { }
+ "N" { return }
+ "F" { setup_xfail "*-*-*" }
+ "P" { }
+ }
+ }
+
+ set testcase [testname-for-summary]
+ set pattern [lindex $args 0]
+ set times [lindex $args 1]
+ set pp_pattern [make_pattern_printable $pattern]
+ set testname [lindex $testcase 0]
+ set basename [file rootname $testname]
+ set output_files [dg_glob_remote "${basename}.ltrans*.s"]
+
+ if { $output_files == "" } {
+ verbose -log "$testcase: no ${basename}.ltrans*.s files found"
+ unresolved "$testcase scan-ltrans-assembler-times $pp_pattern $times"
+ return
+ }
+
+ set total_matches 0
+ foreach file $output_files {
+ set fd [open $file r]
+ set text [read $fd]
+ close $fd
+ set matches [regexp -all -- $pattern $text]
+ set total_matches [expr $total_matches + $matches]
+ }
+
+ if { $total_matches == $times } {
+ pass "$testcase scan-ltrans-assembler-times $pp_pattern $times"
+ } else {
+ verbose -log "$testcase: $pp_pattern found $total_matches times"
+ fail "$testcase scan-ltrans-assembler-times $pp_pattern $times"
+ }
+}
+set_required_options_for scan-ltrans-assembler-times
--
2.34.0