This patch adds D language support to the GCC testsuite. As well as generating the DejaGNU options for compile and link tests, handles the conversion from DMD-style compiler options to GDC.
---
[PATCH 9/13] D: D2 Testsuite Dejagnu files. This patch adds D language support to the GCC testsuite. As well as generating the DejaGNU options for compile and link tests, handles the conversion from DMD-style compiler options to GDC. --- diff --git a/gcc/testsuite/gdc.test/d_do_test.exp b/gcc/testsuite/gdc.test/d_do_test.exp new file mode 100644 index 00000000000..94ea92cf94e --- /dev/null +++ b/gcc/testsuite/gdc.test/d_do_test.exp @@ -0,0 +1,376 @@ +# Copyright (C) 2012-2017 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Test using the DMD testsuite. +# Load support procs. +load_lib gdc-dg.exp + +# Convert DMD arguments to GDC equivalent +proc gdc-convert-args { args } { + set out "" + + foreach arg [split [lindex $args 0] " "] { + # List of switches kept in ASCII collated order. + if { [regexp -- {^-I([\w+/-]+)} $arg pattern path] } { + lappend out "-I$path" + + } elseif { [regexp -- {^-J([\w+/-]+)} $arg pattern path] } { + lappend out "-J$path" + + } elseif [string match "-allinst" $arg] { + lappend out "-femit-templates" + + } elseif { [string match "-boundscheck" $arg] + || [ string match "-boundscheck=on" $arg] } { + lappend out "-fbounds-check" + + } elseif { [string match "-boundscheck=off" $arg] + || [string match "-noboundscheck" $arg] } { + lappend out "-fno-bounds-check" + + } elseif [string match "-boundscheck=safeonly" $arg] { + lappend out "-fbounds-check=safeonly" + + } elseif [string match "-c" $arg] { + lappend out "-c" + + } elseif [string match "-d" $arg] { + lappend out "-Wno-deprecated" + + } elseif [string match "-de" $arg] { + lappend out "-Wdeprecated" + lappend out "-Werror" + + } elseif [string match "-debug" $arg] { + lappend out "-fdebug" + + } elseif [string match "-dip1000" $arg] { + lappend out "-ftransition=safe" + + } elseif [string match "-dip25" $arg] { + lappend out "-ftransition=dip25" + + } elseif [string match "-dw" $arg] { + lappend out "-Wdeprecated" + lappend out "-Wno-error" + + } elseif [string match "-fPIC" $arg] { + lappend out "-fPIC" + + } elseif { [string match "-g" $arg] + || [string match "-gc" $arg] } { + lappend out "-g" + + } elseif [string match "-inline" $arg] { + lappend out "-finline-functions" + + } elseif [regexp -- {^-mv=([\w+=./-]+)} $arg pattern value] { + lappend out "-fmodule-filepath=$value" + + } elseif [string match "-O" $arg] { + lappend out "-O2" + + } elseif [string match "-property" $arg] { + lappend out "-fproperty" + + } elseif [string match "-release" $arg] { + lappend out "-frelease" + + } elseif [regexp -- {^-transition=(\w+)} $arg pattern value] { + lappend out "-ftransition=$value" + + } elseif [string match "-unittest" $arg] { + lappend out "-funittest" + + } elseif [string match "-verrors=spec" $arg] { + lappend out "-Wspeculative" + + } elseif [regexp -- {^-verrors=(\d+)} $arg pattern num] { + lappend out "-fmax-errors=$num" + + } elseif [regexp -- {^-version=(\w+)} $arg pattern value] { + lappend out "-fversion=$value" + + } elseif [string match "-w" $arg] { + lappend out "-Wall" + lappend out "-Werror" + + } elseif [string match "-wi" $arg] { + lappend out "-Wall" + lappend out "-Wno-error" + + } else { + # print "Unhandled Argument: $arg" + } + } + + return $out +} + +proc gdc-copy-extra { base extra } { + # Split base, folder/file. + set type [file dirname $extra ] + + # print "Filename: $base - $extra" + + set fdin [open $base/$extra r] + fconfigure $fdin -encoding binary + + file mkdir [file dirname $extra ] + set fdout [ open $extra w] + fconfigure $fdout -encoding binary + + # print "[file dirname $test ]" + while { [gets $fdin copy_line] >= 0 } { + set out_line $copy_line + puts $fdout $out_line + } + + close $fdin + close $fdout + + return $extra +} + + +# Translate DMD test directives to dejagnu equivalent. +proc dmd2dg { base test } { + global DEFAULT_DFLAGS + global PERMUTE_ARGS + global EXECUTE_ARGS + + set PERMUTE_ARGS $DEFAULT_DFLAGS + set EXECUTE_ARGS "" + + # Split base, folder/file. + set type [file dirname $test] + + # print "Filename: $base - $test" + + set fdin [open $base/$test r] + #fconfigure $fdin -encoding binary + + file mkdir [file dirname $test] + set fdout [ open $test w] + #fconfigure $fdout -encoding binary + + # print "[file dirname $test ]" + + # Add specific options for test type + + # DMD's testsuite is exteremly verbose. + # dg-prune-ouput generates pass. + set out_line "// { dg-prune-output .* }" + puts $fdout $out_line + + # Since GCC 6-20160131 blank lines are not allowed in the + # output by default. + dg-allow-blank-lines-in-output { 1 } + + # Compilable files are successful if an output is generated. + # Fail compilable are successful if an output is not generated. + # Runnable must compile, link, and return 0 to be successful by default. + switch [ file dirname $test ] { + compilable { + set out_line "// { dg-final { output-exists } }" + puts $fdout $out_line + } + + fail_compilation { + set out_line "// { dg-final { output-exists-not } }" + puts $fdout $out_line + } + + } + + while { [gets $fdin copy_line] >= 0 } { + set out_line $copy_line + + # PERMUTE_ARGS. Must be handled separately + if [regexp -- {PERMUTE_ARGS\s*:\s*(.*)} $copy_line match args] { + set PERMUTE_ARGS [gdc-convert-args $args] + continue + } + + # COMPILE_SEPARATELY. Not handled. + if [regexp -- {COMPILE_SEPARATELY} $copy_line] { + continue + } + + # POST_SCRIPT. not handled + if [regexp -- {POST_SCRIPT} $copy_line] { + continue + } + + # Can be handled with dg directives. + + # Handle EXECUTE_ARGS option. + if [regexp -- {EXECUTE_ARGS\s*:\s*(.*)} $copy_line match args] { + foreach arg $args { + lappend EXECUTE_ARGS $arg + } + continue + } + + # Handle EXTRA_SOURCES option + if [regexp -- {EXTRA_SOURCES\s*:\s*(.*)} $copy_line match sources] { + # Iterate imports and convert + foreach import $sources { + # print "Import: $base $type/$import" + gdc-copy-extra $base "$type/$import" + } + set out_line "// { dg-additional-sources \"$sources\" }" + } + + # Handle EXTRA_CPP_SOURCES option + if [regexp -- {EXTRA_CPP_SOURCES\s*:\s*(.*)} $copy_line match sources] { + # Iterate imports and convert + foreach import $sources { + # print "Import: $base $type/$import" + gdc-copy-extra $base "$type/$import" + } + set out_line "// { dg-additional-sources \"$sources\" }" + } + + # Handle EXTRA_FILES option + if [regexp -- {EXTRA_FILES\s*:\s*(.*)} $copy_line match files] { + # Iterate imports and convert + foreach import $files { + # print "Import: $base $type/$import" + gdc-copy-extra $base "$type/$import" + } + set out_line "// { dg-additional-files \"$files\" }" + } + + # REQUIRED_ARGS. + if [regexp -- {REQUIRED_ARGS\s*:\s*(.*)} $copy_line match args] { + set out_line "// { dg-additional-options \"[gdc-convert-args $args]\" }" + } + puts $fdout $out_line + } + + close $fdin + close $fdout + + return $test +} + +proc gdc-permute-options { options } { + set result { } + set n [expr 1<<[llength $options]] + for { set i 0 } { $i<$n } { incr i } { + set option "" + for { set j 0 } { $j<[llength $options] } { incr j } { + if [expr $i & 1 << $j] { + append option [lindex $options $j] + append option " " + } + } + lappend result $option + + } + return $result +} + + +proc gdc-do-test { } { + global TORTURE_OPTIONS + global SHARED_OPTION + global srcdir subdir + global dg-do-what-default + global verbose + + # If a testcase doesn't have special options, use these. + global DEFAULT_DFLAGS + if ![info exists DEFAULT_DFLAGS] then { + set DEFAULT_DFLAGS "-g -O2 -frelease" + #set DEFAULT_DFLAGS "-O2" + } + + # These are special options to use on testcase, and override DEFAULT_DFLAGS + global PERMUTE_ARGS + + # Additional arguments for gdc_load + global EXECUTE_ARGS + + # Initialize `dg'. + dg-init + + # Main loop. + + # set verbose 1 + # set dg-final-code "" + # Find all tests and pass to routine. + foreach test [lsort [find $srcdir/$subdir *]] { + regexp -- "(.*)/(.+)/(.+)\.(.+)$" $test match base dir name ext + + # Skip invalid test directory + if {[lsearch "runnable compilable fail_compilation" $dir] == -1} { + continue + } + + # Skip invalid test extensions + if {[lsearch "d" $ext] == -1} { + continue + } + + # Convert to DG test. + set imports [file dirname $test] + set imports [format "-I%s -I%s/imports" $imports $imports] + set filename [dmd2dg $base $dir/$name.$ext] + + if {$dir == "runnable"} { + append PERMUTE_ARGS " $SHARED_OPTION" + } + set options [gdc-permute-options $PERMUTE_ARGS] + + switch $dir { + runnable { + for { set i 0 } { $i<[llength $options] } { incr i } { + set TORTURE_OPTIONS [lindex $options $i] + set dg-do-what-default "run" + gdc-dg-runtest $filename $imports + } + } + + compilable { + for { set i 0 } { $i<[llength $options] } { incr i } { + set TORTURE_OPTIONS [lindex $options $i] + set dg-do-what-default "assemble" + gdc-dg-runtest $filename "$imports" + } + } + + fail_compilation { + for { set i 0 } { $i<[llength $options] } { incr i } { + set TORTURE_OPTIONS [lindex $options $i] + set dg-do-what-default "assemble" + #set dg-do-what-default "compile" + gdc-dg-runtest $filename $imports + } + } + } + + # Cleanup + #file delete $filename + } + + # All done. + dg-finish +} + +gdc-do-test + diff --git a/gcc/testsuite/lib/gdc-dg.exp b/gcc/testsuite/lib/gdc-dg.exp new file mode 100644 index 00000000000..a8003f4ad01 --- /dev/null +++ b/gcc/testsuite/lib/gdc-dg.exp @@ -0,0 +1,82 @@ +# Copyright (C) 2012-2017 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +load_lib gcc-dg.exp + +# Define go callbacks for dg.exp. + +proc gdc-dg-test { prog do_what extra_tool_flags } { + set result \ + [gcc-dg-test-1 gdc_target_compile $prog $do_what $extra_tool_flags] + + set comp_output [lindex $result 0] + set output_file [lindex $result 1] + + return [list $comp_output $output_file] +} + +proc gdc-dg-prune { system text } { + return [gcc-dg-prune $system $text] +} + +# Utility routines. + +# Modified dg-runtest that can cycle through a list of optimization options +# as c-torture does. +proc gdc-dg-runtest { testcases default-extra-flags } { + global runtests + global TORTURE_OPTIONS + + foreach test $testcases { + # If we're only testing specific files and this isn't one of + # them, skip it. + if ![runtest_file_p $runtests $test] { + continue + } + + if [expr [search_for $test "dg-do run"]] { + set flags "" + } else { + set flags $TORTURE_OPTIONS + } + + # Use dg-options if specified + #dg-options + + set nshort [file tail [file dirname $test]]/[file tail $test] + verbose "Testing $nshort, $TORTURE_OPTIONS" 1 + dg-test $test $TORTURE_OPTIONS ${default-extra-flags} + } +} + +# +# gdc_load -- wrapper around default gdc_load to handle tests that +# require program arguments passed to them. +# + +if { [info procs gdc_load] != [list] \ + && [info procs prev_gdc_load] == [list] } { + rename gdc_load prev_gdc_load + + proc gdc_load { program args } { + global EXECUTE_ARGS + set args [concat "{$EXECUTE_ARGS}"] + #print "Running: $program [lindex $args 0]" + set result [eval [list prev_gdc_load $program] $args ] + return $result + } +} + diff --git a/gcc/testsuite/lib/gdc.exp b/gcc/testsuite/lib/gdc.exp new file mode 100644 index 00000000000..8035d4eacdf --- /dev/null +++ b/gcc/testsuite/lib/gdc.exp @@ -0,0 +1,274 @@ +# Copyright (C) 2012-2017 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# +# gdc support library routines +# +load_lib prune.exp +load_lib gcc-defs.exp +load_lib timeout.exp +load_lib target-libpath.exp + +# +# GDC_UNDER_TEST is the compiler under test. +# + + +set gdc_compile_options "" + + +# +# gdc_version -- extract and print the version number of the compiler +# + +proc gdc_version { } { + global GDC_UNDER_TEST + + gdc_init + + # ignore any arguments after the command + set compiler [lindex $GDC_UNDER_TEST 0] + + # verify that the compiler exists + if { [is_remote host] || [which $compiler] != 0 } then { + set tmp [remote_exec host "$compiler -v"] + set status [lindex $tmp 0] + set output [lindex $tmp 1] + regexp " version \[^\n\r\]*" $output version + if { $status == 0 && [info exists version] } then { + if [is_remote host] { + clone_output "$compiler $version\n" + } else { + clone_output "[which $compiler] $version\n" + } + } else { + clone_output "Couldn't determine version of [which $compiler]\n" + } + } else { + # compiler does not exist (this should have already been detected) + warning "$compiler does not exist" + } +} + +# +# gdc_include_flags -- include flags for the gcc tree structure +# + +proc gdc_include_flags { paths } { + global srcdir + global TESTING_IN_BUILD_TREE + + set flags "" + + if { [is_remote host] || ![info exists TESTING_IN_BUILD_TREE] } { + return "${flags}" + } + + set gccpath ${paths} + set target [file tail [file normalize ${paths}]] + + if { $gccpath != "" } { + if [file exists "${gccpath}/libphobos/libdruntime"] { + append flags "-I${gccpath}/libphobos/libdruntime " + } + } + append flags "-I${srcdir}/../../libphobos/libdruntime " + append flags "-I${srcdir}/../../libphobos/src " + + # For the tests that mix C++ and D, we should try and handle this better. + if { $gccpath != "" } { + if [file exists "${gccpath}/libstdc++-v3/include"] { + append flags "-I${gccpath}/libstdc++-v3/include " + append flags "-I${gccpath}/libstdc++-v3/include/$target " + } + } + append flags "-I${srcdir}/../../libstdc++-v3/libsupc++" +} + +# +# gdc_link_flags -- linker flags for the gcc tree structure +# + +proc gdc_link_flags { paths } { + global srcdir + global ld_library_path + global GDC_UNDER_TEST + global shlib_ext + global SHARED_OPTION + + set gccpath ${paths} + set libio_dir "" + set flags "" + set ld_library_path "." + set shlib_ext [get_shlib_extension] + set SHARED_OPTION "" + verbose "shared lib extension: $shlib_ext" + + if { $gccpath != "" } { + if { [file exists "${gccpath}/libphobos/src/.libs/libgphobos.a"] \ + || [file exists "${gccpath}/libphobos/src/.libs/libgphobos.${shlib_ext}"] } { + append flags "-L${gccpath}/libphobos/src/.libs -B${gccpath}/libphobos/src " + append ld_library_path ":${gccpath}/libphobos/src/.libs" + } + if { [file exists "${gccpath}/libphobos/libdruntime/.libs/libgdruntime.a"] \ + || [file exists "${gccpath}/libphobos/libdruntime/.libs/libgdruntime.${shlib_ext}"] } { + append flags "-L${gccpath}/libphobos/libdruntime/.libs " + append ld_library_path ":${gccpath}/libphobos/libdruntime/.libs" + } + # Static linking is default. If only the shared lib is available adjust + # flags to always use it. If both are available, set SHARED_OPTION which + # will be added to PERMUTE_ARGS + if { [file exists "${gccpath}/libphobos/libdruntime/.libs/libgdruntime.${shlib_ext}"] } { + if { [file exists "${gccpath}/libphobos/libdruntime/.libs/libgdruntime.a"] } { + set SHARED_OPTION "-shared-libphobos" + } else { + append flags "-shared-libphobos " + } + } + if [file exists "${gccpath}/libiberty/libiberty.a"] { + append flags "-L${gccpath}/libiberty " + } + # For the tests that mix C++ and D, we should try and handle this better. + if { [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] \ + || [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] } { + append flags "-L${gccpath}/libstdc++-v3/src/.libs " + append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" + } + append ld_library_path [gcc-set-multilib-library-path $GDC_UNDER_TEST] + } else { + global tool_root_dir + + set libphobos [lookfor_file ${tool_root_dir} libgphobos] + if { $libphobos != "" } { + append flags "-L${libphobos} " + append ld_library_path ":${libphobos}" + } + set libdruntime [lookfor_file ${tool_root_dir} libgdruntime] + if { $libdruntime != "" } { + append flags "-L${libdruntime} " + append ld_library_path ":${libdruntime}" + } + set libiberty [lookfor_file ${tool_root_dir} libiberty] + if { $libiberty != "" } { + append flags "-L${libiberty} " + } + } + + set_ld_library_path_env_vars + + return "$flags" +} + +# +# gdc_init -- called at the start of each subdir of tests +# + +proc gdc_init { args } { + global subdir + global gdc_initialized + global base_dir + global tmpdir + global libdir + global gluefile wrap_flags + global objdir srcdir + global ALWAYS_DFLAGS + global TOOL_EXECUTABLE TOOL_OPTIONS + global GDC_UNDER_TEST + global TESTING_IN_BUILD_TREE + global TEST_ALWAYS_FLAGS + + # We set LC_ALL and LANG to C so that we get the same error messages as expected. + setenv LC_ALL C + setenv LANG C + + if ![info exists GDC_UNDER_TEST] then { + if [info exists TOOL_EXECUTABLE] { + set GDC_UNDER_TEST $TOOL_EXECUTABLE + } else { + if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } { + set GDC_UNDER_TEST [transform gdc] + } else { + set GDC_UNDER_TEST [findfile $base_dir/../../gdc "$base_dir/../../gdc -B$base_dir/../../" [findfile $base_dir/gdc "$base_dir/gdc -B$base_dir/" [transform gdc]]] + } + } + } + + if ![is_remote host] { + if { [which $GDC_UNDER_TEST] == 0 } then { + perror "GDC_UNDER_TEST ($GDC_UNDER_TEST) does not exist" + exit 1 + } + } + if ![info exists tmpdir] { + set tmpdir "/tmp" + } + + if [info exists gluefile] { + unset gluefile + } + + gdc_maybe_build_wrapper "${tmpdir}/d-testglue.o" + + set ALWAYS_DFLAGS "" + + # TEST_ALWAYS_FLAGS are flags that should be passed to every + # compilation. They are passed first to allow individual + # tests to override them. + if [info exists TEST_ALWAYS_FLAGS] { + lappend ALWAYS_DFLAGS "additional_flags=$TEST_ALWAYS_FLAGS" + } + + if ![is_remote host] { + if [info exists TOOL_OPTIONS] { + lappend ALWAYS_DFLAGS "additional_flags=[gdc_include_flags [get_multilibs ${TOOL_OPTIONS}] ]" + lappend ALWAYS_DFLAGS "ldflags=[gdc_link_flags [get_multilibs ${TOOL_OPTIONS}] ]" + } else { + lappend ALWAYS_DFLAGS "additional_flags=[gdc_include_flags [get_multilibs] ]" + lappend ALWAYS_DFLAGS "ldflags=[gdc_link_flags [get_multilibs] ]" + } + } + + if [info exists TOOL_OPTIONS] { + lappend ALWAYS_DFLAGS "additional_flags=$TOOL_OPTIONS" + } + + verbose -log "ALWAYS_DFLAGS set to $ALWAYS_DFLAGS" + + verbose "gdc is initialized" 3 +} + +# +# gdc_target_compile -- compile a source file +# + +proc gdc_target_compile { source dest type options } { + global tmpdir + global gluefile wrap_flags + global ALWAYS_DFLAGS + global GDC_UNDER_TEST + + if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } { + lappend options "libs=${gluefile}" + lappend options "ldflags=${wrap_flags}" + } + + lappend options "timeout=[timeout_value]" + lappend options "compiler=$GDC_UNDER_TEST" + + set options [concat "$ALWAYS_DFLAGS" $options] + set options [dg-additional-files-options $options $source] + return [target_compile $source $dest $type $options] +}