blob: ffbaa277e8ed0a1c604de86b2df2513888aa6bef [file] [log] [blame]
# Copyright (C) 2012-2022 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.
#
# 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 [string match "-D" $arg] {
upvar 1 compilable_output_file_ext compilable_output_file_ext
set compilable_output_file_ext "html"
lappend out "-fdoc"
} elseif [string match "-H" $arg] {
upvar 1 compilable_output_file_ext compilable_output_file_ext
set compilable_output_file_ext "di"
lappend out "-H"
} elseif [string match "-HC" $arg] {
upvar 1 compilable_output_file_ext compilable_output_file_ext
upvar 1 name name
set compilable_output_file_ext "h"
lappend out "-fdump-c++-spec=[file rootname $name].h"
} elseif [string match "-HC=verbose" $arg] {
lappend out "-fdump-c++-spec-verbose"
} elseif { [regexp -- {^-I([\w+/-]+)} $arg pattern path] } {
lappend out "-I$path"
} elseif { [regexp -- {^-J([\w+/-]+)} $arg pattern path] } {
lappend out "-J$path"
} elseif [string match "-X" $arg] {
upvar 1 compilable_output_file_ext compilable_output_file_ext
set compilable_output_file_ext "json"
lappend out "-X"
} elseif [string match "-allinst" $arg] {
lappend out "-fall-instantiations"
} elseif [string match "-betterC" $arg] {
lappend out "-fno-druntime"
} elseif { [string match "-boundscheck" $arg]
|| [string match "-boundscheck=on" $arg] } {
lappend out "-fbounds-check=on"
} elseif { [string match "-boundscheck=off" $arg]
|| [string match "-noboundscheck" $arg] } {
lappend out "-fbounds-check=off"
} elseif [string match "-boundscheck=safeonly" $arg] {
lappend out "-fbounds-check=safeonly"
} elseif [string match "-c" $arg] {
lappend out "-c"
} elseif [regexp -- {^-check=(\w+)=off} $arg pattern value] {
lappend out "-fno-check=$value"
} elseif [string match "-checkaction=context" $arg] {
lappend out "-fcheckaction=context"
} 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 [regexp -- {^-debug=(\w+)} $arg pattern value] {
lappend out "-fdebug=$value"
} elseif [string match "-dip25" $arg] {
lappend out "-fpreview=dip25"
} elseif [string match "-dip1000" $arg] {
lappend out "-fpreview=dip1000"
} elseif [string match "-dip1008" $arg] {
lappend out "-fpreview=dip1008"
} elseif [string match "-dw" $arg] {
lappend out "-Wdeprecated"
lappend out "-Wno-error"
} elseif [regexp -- {^-extern-std=([\w+]+)} $arg pattern value] {
lappend out "-fextern-std=$value"
} elseif [string match "-fPIC" $arg] {
lappend out "-fPIC"
} elseif [string match "-fPIE" $arg] {
lappend out "-fPIE"
} elseif { [string match "-g" $arg]
|| [string match "-gc" $arg] } {
lappend out "-g"
} elseif [string match "-ignore" $arg] {
lappend out "-fignore-unknown-pragmas"
} elseif [string match "-inline" $arg] {
lappend out "-finline-functions"
} elseif [string match "-main" $arg] {
lappend out "-fmain"
} elseif [regexp -- {^-mv=([\w+=./-]+)} $arg pattern value] {
lappend out "-fmodule-file=$value"
} elseif [string match "-O" $arg] {
lappend out "-O2"
} elseif [regexp -- {^-preview=(\w+)} $arg pattern value] {
lappend out "-fpreview=[string tolower $value]"
} elseif [string match "-release" $arg] {
lappend out "-frelease"
} elseif [regexp -- {^-revert=(\w+)} $arg pattern value] {
lappend out "-frevert=[string tolower $value]"
} elseif [regexp -- {^-transition=(\w+)} $arg pattern value] {
lappend out "-ftransition=[string tolower $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 "-o-" $arg] {
upvar 2 compilable_do_what compilable_do_what
set compilable_do_what "compile"
} elseif [string match "-vgc" $arg] {
lappend out "-ftransition=nogc"
} elseif [string match "-vtemplates" $arg] {
lappend out "-ftransition=templates"
} elseif [string match "-vtls" $arg] {
lappend out "-ftransition=tls"
} 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-file { srcdir filename } {
# Split folder/file from the filename.
set targetdir [file dirname $filename]
# print "Filename: $srcdir - $filename"
file mkdir $targetdir
file copy -force $srcdir/$filename $filename
# Remove file once test is finished.
upvar 2 cleanup_extra_files cleanups
lappend cleanups $filename
}
#
# Translate DMD test directives to dejagnu equivalent.
#
# This procedure copies the test and all its dependencies from its source
# location in `$srcdir/$type' to `$base_dir/$type'. A stub dejagnu test file
# is then created in `$base_dir/gdc.test/$type' containing all translated test
# directives. This stub is then the test that is handed over to `dg-test'.
# Before invoking the compiler, the `gdc.test' prefix is trimmed from the test
# `$prog' name in `gdc-dg-test' so that all copied tests then get picked up
# with the correct path names.
#
# The following directives are recognized:
#
# COMPILE_SEPARATELY: Not handled.
# EXECUTE_ARGS: Parameters to add to the execution of the test.
# COMPILED_IMPORTS: List of modules files that are imported by the main
# source file that should be included in compilation.
# Currently handled the same as EXTRA_SOURCES.
# DFLAGS: Overrides the DFLAGS environment variable if specified
# in the test. No values are permitted; an error will be
# emitted if the value is not empty.
# EXTRA_SOURCES: List of extra sources to build and link along with
# the test.
# EXTRA_CPP_SOURCES: List of extra C++ files to build and link along with
# the test.
# CXXFLAGS: list of extra arguments passed when compiling C++
# sources defined in EXTRA_CPP_SOURCES.
# EXTRA_OBJC_SOURCES: List of extra Objective-C file to build and link along
# with the test. Currently not handled.
# EXTRA_FILES: List of extra files to copy for the test runs.
# PERMUTE_ARGS: The set of arguments to permute in multiple compiler
# invocations. An empty set means only one permutation
# with no arguments.
# ARG_SETS: Not handled.
# LINK: Enables linking.
# TEST_OUTPUT: The output expected from the compilation.
# POST_SCRIPT: Not handled.
# REQUIRED_ARGS: Arguments to add to the compiler command line.
# DISABLED: Not handled.
#
proc gdc-convert-test { base test } {
global DEFAULT_DFLAGS
global PERMUTE_ARGS
global GDC_EXECUTE_ARGS
set PERMUTE_ARGS ""
set GDC_EXECUTE_ARGS ""
set extra_sources ""
set extra_files ""
set needs_phobos 0
set saw_test_flags 0
upvar 1 compilable_do_what compilable_do_what
set compilable_output_file_ext ""
# Split folder/file from the test.
set type [file dirname $test]
set name [file tail $test]
# print "Filename: $base - $test"
gdc-copy-file $base $test
# Read in all test directives, and save the dejagnu equivalents to a new
# file that will be returned as the test to run.
set fdin [open $base/$test r]
#fconfigure $fdin -encoding binary
# Include gdc.test prefix so test names follow DejaGnu conventions.
set testdir [file tail $base]
file mkdir $testdir/$type
set fdout [open $testdir/$test w]
#fconfigure $fdout -encoding binary
while { [gets $fdin copy_line] >= 0 } {
if [regexp -- {COMPILE_SEPARATELY} $copy_line] {
# COMPILE_SEPARATELY is not handled.
} elseif [regexp -- {DISABLED} $copy_line] {
# DISABLED is not handled.
} elseif [regexp -- {LINK:} $copy_line] {
# LINK sets dg-do-what-default "link"
set compilable_do_what "link"
} elseif [regexp -- {ARG_SETS} $copy_line] {
# ARG_SETS is not handled.
regsub -- {ARG_SETS.*$} $copy_line "" out_line
} elseif [regexp -- {POST_SCRIPT} $copy_line] {
# POST_SCRIPT is not handled
} elseif [regexp -- {DFLAGS\s*:\s*(.*)} $copy_line match args] {
# DFLAGS overrides the default value of PERMUTE_ARGS.
if { $args != "" } {
error "gdc-convert-test: DFLAGS is not empty as expected"
}
set saw_test_flags 1
} elseif [regexp -- {PERMUTE_ARGS\s*:\s*(.*)} $copy_line match args] {
# PERMUTE_ARGS is handled by gdc-do-test.
set PERMUTE_ARGS [gdc-convert-args $args]
set saw_test_flags 1
} elseif [regexp -- {EXECUTE_ARGS\s*:\s*(.*)} $copy_line match args] {
# EXECUTE_ARGS is handled by gdc_load.
foreach arg $args {
lappend GDC_EXECUTE_ARGS $arg
}
} elseif [regexp -- {REQUIRED_ARGS\s*:\s*(.*)} $copy_line match args] {
# Convert all listed arguments to from dmd to gdc-style.
puts $fdout "// { dg-additional-options \"[gdc-convert-args $args]\" }"
} elseif [regexp -- {EXTRA_SOURCES\s*:\s*(.*)} $copy_line match sources] {
# EXTRA_SOURCES are appended to extra_sources list
foreach srcfile $sources {
lappend extra_sources $srcfile
}
} elseif [regexp -- {EXTRA_CPP_SOURCES\s*:\s*(.*)} $copy_line match sources] {
# EXTRA_CPP_SOURCES are appended to extra_sources list
foreach srcfile $sources {
# C++ sources are found in the extra-files directory.
lappend extra_sources "extra-files/$srcfile"
}
} elseif [regexp -- {CXXFLAGS\s*:\s*(.*)} $copy_line match args] {
# Both C++ and D sources are compiled together, so include each
# other's command line flags too.
set new_option "{ dg-additional-options \"$args\" }"
regsub -- {CXXFLAGS.*$} $copy_line $new_option out_line
} elseif [regexp -- {EXTRA_OBJC_SOURCES\s*:\s*(.*)} $copy_line match sources] {
# EXTRA_OBJC_SOURCES is not handled.
regsub -- {EXTRA_OBJC_SOURCES.*$} $copy_line "" out_line
} elseif [regexp -- {EXTRA_FILES\s*:\s*(.*)} $copy_line match files] {
# EXTRA_FILES are appended to extra_files list
foreach file $files {
lappend extra_files $file
}
} elseif [regexp -- {COMPILED_IMPORTS\s*:\s*(.*)} $copy_line match sources] {
# COMPILED_IMPORTS are appended to extra_sources list
foreach import $sources {
lappend extra_sources $import
}
} elseif [regexp -- {RUNNABLE_PHOBOS_TEST} $copy_line match sources] {
# RUNNABLE_PHOBOS_TEST annotates tests that import the std module.
# It will need skipping if phobos is not available on the target.
set needs_phobos 1
} elseif [regexp -- {COMPILABLE_MATH_TEST} $copy_line match sources] {
# COMPILABLE_MATH_TEST annotates tests that import the std.math
# module. Which will need skipping if not available on the target.
set needs_phobos 1
}
}
# Now that all extra sources and files have been collected, copy them all
# to the testsuite build directory.
if { [llength $extra_sources] > 0 } {
foreach srcfile $extra_sources {
gdc-copy-file $base "$type/$srcfile"
}
puts $fdout "// { dg-additional-sources \"$extra_sources\" }"
}
if { [llength $extra_files] > 0 } {
foreach file $extra_files {
gdc-copy-file $base "$type/$file"
}
puts $fdout "// { dg-additional-files \"$extra_files\" }"
}
# Add specific options for test type
# DMD's testsuite is extremely verbose, compiler messages from constructs
# such as pragma(msg, ...) would otherwise cause tests to fail.
puts $fdout "// { dg-prune-output .* }"
# 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 $type {
runnable_cxx -
runnable {
if ![isnative] {
puts $fdout "// { dg-final { output-exists } }"
}
if $needs_phobos {
puts $fdout "// { dg-skip-if \"imports phobos\" { ! d_runtime_has_std_library } }"
}
# Run runnable tests with all default permutations if not
# explicitly set in the test file.
if !$saw_test_flags {
set PERMUTE_ARGS $DEFAULT_DFLAGS
}
}
compilable {
puts $fdout "// { dg-final { output-exists } }"
# Compilable test may require checking another kind of output file.
if { $compilable_output_file_ext != "" } {
# Check that file generation tests output the expected file.
set genfile "[file rootname $name].$compilable_output_file_ext"
puts $fdout "// { dg-final { if \[file exists $genfile\] \\{ } }"
puts $fdout "// { dg-final { pass \"$testdir/$test (file exists $genfile)\" } }"
puts $fdout "// { dg-final { \\} else \\{ } }"
puts $fdout "// { dg-final { fail \"$testdir/$test (file exists $genfile)\" } }"
puts $fdout "// { dg-final { \\} } }"
# Cleanup extra generated files.
puts $fdout "// { dg-final { file delete $genfile } }"
}
if $needs_phobos {
puts $fdout "// { dg-skip-if \"imports phobos\" { ! d_runtime_has_std_library } }"
}
}
fail_compilation {
# Fail compilation tests only check for language errors from the
# front-end. No need to run all permutations of the default DFLAGS.
if { $PERMUTE_ARGS == $DEFAULT_DFLAGS } {
set PERMUTE_ARGS ""
}
puts $fdout "// { dg-final { output-exists-not } }"
}
}
close $fdin
close $fdout
return $testdir/$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
}
#
# Main loop for running all tests for the subdirectory in gdc.test
#
proc gdc-do-test { testcases } {
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
# Set if an extra option should be passed to link to shared druntime.
global SHARED_OPTION
# Additional arguments for gdc_load
global GDC_EXECUTE_ARGS
# Allow blank linkes in output for all of gdc.test.
global allow_blank_lines
set save_allow_blank_lines $allow_blank_lines
if { !$allow_blank_lines } {
set allow_blank_lines 2
}
set saved-dg-do-what-default ${dg-do-what-default}
# Main loop.
# set verbose 1
# set dg-final-code ""
# Find all tests and pass to routine.
foreach test $testcases {
regexp -- "(.*)/(.+)/(.+)\.(.+)$" $test match base type name ext
# Convert to DG test.
set imports [format "-I%s" $type]
set cleanup_extra_files ""
set compilable_do_what "compile"
set filename "[gdc-convert-test $base $type/$name.$ext]"
if { $type == "runnable" || $type == "runnable_cxx" } {
append PERMUTE_ARGS " $SHARED_OPTION"
}
set options [gdc-permute-options [lsort -unique $PERMUTE_ARGS]]
switch $type {
runnable_cxx -
runnable {
for { set i 0 } { $i<[llength $options] } { incr i } {
set flags [lindex $options $i]
if [isnative] {
set dg-do-what-default "run"
} else {
set dg-do-what-default "link"
}
gdc-dg-runtest $filename $flags $imports
}
}
compilable {
for { set i 0 } { $i<[llength $options] } { incr i } {
set flags [lindex $options $i]
set dg-do-what-default $compilable_do_what
gdc-dg-runtest $filename $flags $imports
}
}
fail_compilation {
for { set i 0 } { $i<[llength $options] } { incr i } {
set flags [lindex $options $i]
set dg-do-what-default "assemble"
gdc-dg-runtest $filename $flags $imports
}
}
}
# Cleanup test directory.
foreach srcfile $cleanup_extra_files {
file delete $srcfile
}
file delete $filename
}
set dg-do-what-default ${saved-dg-do-what-default}
set allow_blank_lines $save_allow_blank_lines
}