diff -Nru ldc-1.6.0/appveyor.yml ldc-1.8.0/appveyor.yml --- ldc-1.6.0/appveyor.yml 2018-01-03 19:40:41.000000000 +0000 +++ ldc-1.8.0/appveyor.yml 2018-03-12 22:13:02.000000000 +0000 @@ -4,25 +4,22 @@ #version: 1.0.{build}-{branch} -# Do not build on tags (GitHub only) -skip_tags: true - #---------------------------------# # environment configuration # #---------------------------------# environment: matrix: - - APPVEYOR_JOB_ARCH: x64 + - APPVEYOR_JOB_ARCH: x64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + LLVM_VERSION: 5.0.1 + HOST_LDC_VERSION: 1.6.0 + DUB_VERSION: v1.7.2 + - APPVEYOR_JOB_ARCH: x86 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - D_COMPILER: ldc - - APPVEYOR_JOB_ARCH: x86 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - D_COMPILER: ldc - -#matrix: -# allow_failures: -# - APPVEYOR_JOB_ARCH: x86 + LLVM_VERSION: 5.0.1 + HOST_LDC_VERSION: 1.6.0 + DUB_VERSION: v1.7.2 # scripts that are called at very beginning, before repo cloning init: @@ -41,13 +38,19 @@ - cd libcurl - 7z x ..\libcurl.zip > nul - cd .. - # Copy libcurl.dll to final LDC installation directory and add to PATH - - md ldc-%APPVEYOR_JOB_ARCH% && md ldc-%APPVEYOR_JOB_ARCH%\bin - - if "%APPVEYOR_JOB_ARCH%"=="x64" ( copy libcurl\dmd2\windows\bin64\libcurl.dll ldc-x64\bin ) - - if "%APPVEYOR_JOB_ARCH%"=="x86" ( copy libcurl\dmd2\windows\bin\libcurl.dll ldc-x86\bin ) - - set PATH=%CD%\ldc-%APPVEYOR_JOB_ARCH%\bin;%PATH% + # Copy libcurl.{dll,lib} to final LDC installation directory and add to PATH + - md ldc2-%APPVEYOR_JOB_ARCH% && md ldc2-%APPVEYOR_JOB_ARCH%\bin && md ldc2-%APPVEYOR_JOB_ARCH%\lib + - ps: | + If ($Env:APPVEYOR_JOB_ARCH -eq 'x64') { + cp libcurl\dmd2\windows\bin64\libcurl.dll ldc2-x64\bin + cp libcurl\dmd2\windows\lib64\curl.lib ldc2-x64\lib + } Else { + cp libcurl\dmd2\windows\bin\libcurl.dll ldc2-x86\bin + cp libcurl\dmd2\windows\lib32mscoff\curl.lib ldc2-x86\lib + } + - set PATH=%CD%\ldc2-%APPVEYOR_JOB_ARCH%\bin;%PATH% # Download & extract Ninja - - appveyor DownloadFile "https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-win.zip" -FileName ninja.zip + - appveyor DownloadFile "https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-win.zip" -FileName ninja.zip - md ninja - cd ninja - 7z x ..\ninja.zip > nul @@ -59,24 +62,23 @@ - python -c "import lit; lit.main();" --version # Download & extract D compiler - ps: | - If ($Env:D_COMPILER -eq 'dmd') { - $dmdVersion = '2.075.1' - appveyor DownloadFile "http://downloads.dlang.org/releases/2.x/$dmdVersion/dmd.$dmdVersion.windows.7z" -FileName dmd2.7z - 7z x dmd2.7z > $null - Set-Item -path env:DMD -value c:\projects\dmd2\windows\bin\dmd.exe + If (Test-Path Env:HOST_LDC_VERSION) { + $ldcVersion = $Env:HOST_LDC_VERSION + If ($Env:APPVEYOR_JOB_ARCH -eq 'x64') { + appveyor DownloadFile "http://github.com/ldc-developers/ldc/releases/download/v$ldcVersion/ldc2-$ldcVersion-win64-msvc.zip" -FileName ldc2.zip + 7z x ldc2.zip > $null + Set-Item -path env:DMD -value "c:\projects\ldc2-$ldcVersion-win64-msvc\bin\ldmd2.exe" + } Else { + appveyor DownloadFile "http://github.com/ldc-developers/ldc/releases/download/v$ldcVersion/ldc2-$ldcVersion-win32-msvc.zip" -FileName ldc2.zip + 7z x ldc2.zip > $null + Set-Item -path env:DMD -value "c:\projects\ldc2-$ldcVersion-win32-msvc\bin\ldmd2.exe" + } } Else { - $ldcVersion = '1.3.0' - If ($Env:APPVEYOR_JOB_ARCH -eq 'x64') { - appveyor DownloadFile "http://github.com/ldc-developers/ldc/releases/download/v$ldcVersion/ldc2-$ldcVersion-win64-msvc.zip" -FileName ldc2.zip - 7z x ldc2.zip > $null - Set-Item -path env:DMD -value c:\projects\ldc2-$ldcVersion-win64-msvc\bin\ldmd2.exe - } Else { - appveyor DownloadFile "http://github.com/ldc-developers/ldc/releases/download/v$ldcVersion/ldc2-$ldcVersion-win32-msvc.zip" -FileName ldc2.zip - 7z x ldc2.zip > $null - Set-Item -path env:DMD -value c:\projects\ldc2-$ldcVersion-win32-msvc\bin\ldmd2.exe - } + $dmdVersion = $Env:HOST_DMD_VERSION + appveyor DownloadFile "http://downloads.dlang.org/releases/2.x/$dmdVersion/dmd.$dmdVersion.windows.7z" -FileName dmd.7z + 7z x dmd.7z > $null + Set-Item -path env:DMD -value c:\projects\dmd2\windows\bin\dmd.exe } - & $Env:DMD --version # Download & extract GNU make + utils (for dmd-testsuite) - bash --version - appveyor DownloadFile "https://dl.dropboxusercontent.com/s/4y36f5ydgrk4p5g/make-4.2.1.7z?dl=0" -FileName make.7z @@ -85,8 +87,14 @@ - 7z x ..\make.7z > nul - make --version - cd .. - # Download & extract a pre-built LLVM (CMAKE_BUILD_TYPE=Release, LLVM_ENABLE_ASSERTIONS=ON) - - appveyor DownloadFile "https://github.com/ldc-developers/llvm/releases/download/ldc-v5.0.0-2/appveyor-llvm-5.0.0-2-%APPVEYOR_JOB_ARCH%.7z" -FileName llvm.7z + # Download & extract LDC-flavoured LLVM + - ps: | + $assertsSuffix = '' + If (!(Test-Path Env:APPVEYOR_REPO_TAG_NAME)) { + echo 'Using LLVM with enabled assertions' + $assertsSuffix = '-withAsserts' + } + appveyor DownloadFile "https://github.com/ldc-developers/llvm/releases/download/ldc-v$Env:LLVM_VERSION/llvm-$Env:LLVM_VERSION-windows-$Env:APPVEYOR_JOB_ARCH$assertsSuffix.7z" -FileName llvm.7z - md llvm - cd llvm - 7z x ..\llvm.7z > nul @@ -105,66 +113,20 @@ # build configuration # #---------------------------------# -before_build: - build_script: - cd c:\projects - # Generate build files for LDC + # Build bootstrap LDC + - md bootstrap + - cd bootstrap + - cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ROOT_DIR=c:/projects/llvm ..\ldc + - ninja -j3 all + - cd .. + # Build LDC and stdlib unittest runners - md ninja-ldc - cd ninja-ldc - - cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=c:\projects\ldc-%APPVEYOR_JOB_ARCH% -DLLVM_ROOT_DIR=c:/projects/llvm ..\ldc - # Build LDC and stdlib unittest runners + - cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=c:\projects\ldc2-%APPVEYOR_JOB_ARCH% -DINCLUDE_INSTALL_DIR=c:/projects/ldc2-%APPVEYOR_JOB_ARCH%/import -DLLVM_ROOT_DIR=c:/projects/llvm -DD_COMPILER=c:\projects\bootstrap\bin\ldmd2.exe ..\ldc - ninja -j2 all all-test-runners -after_build: - # install LDC, compress & publish as artifact - - ps: | - echo 'Preparing artifact...' - cd c:\projects\ninja-ldc - ninja install > $null - copy bin\ldc2.pdb "..\ldc-$Env:APPVEYOR_JOB_ARCH\bin" - cd "..\ldc-$Env:APPVEYOR_JOB_ARCH" - (gc etc\ldc2.conf).replace("C:/projects/ldc-$Env:APPVEYOR_JOB_ARCH/", '%%ldcbinarypath%%/../') | sc etc\ldc2.conf - $artifactFilename = "LDC-master-$Env:APPVEYOR_BUILD_NUMBER-$Env:APPVEYOR_JOB_ARCH.7z" - 7z a "..\$artifactFilename" * > $null - cd .. - Push-AppveyorArtifact $artifactFilename - # x86 job: Create a 32/64-bit multilib artifact if the commit is on the master branch. - # It consists of the x64 artifact (published by a successful x64 job) downloaded from - # GitHub, augmented by the 32-bit libs and an extra section in the ldc2.conf file for `-m32` - # (using the lib32 directory). - - ps: | - If (($Env:APPVEYOR_REPO_BRANCH -eq 'master') -And !(Test-Path Env:APPVEYOR_PULL_REQUEST_NUMBER) -And ($Env:APPVEYOR_JOB_ARCH -eq 'x86')) { - echo 'Preparing 32/64-bit multilib artifact...' - cd c:\projects - $artifact64Downloaded = $True - Try { - (New-Object Net.WebClient).DownloadFile("https://github.com/ldc-developers/ldc/releases/download/LDC-Win64-master/LDC-master-$Env:APPVEYOR_BUILD_NUMBER-x64.7z", 'c:\projects\LDC-master-x64.7z') - } - Catch { - echo 'Failed to download the 64-bit artifact from GitHub (the x64 job probably failed).' - echo 'Skipping the 32/64-bit multilib artifact.' - $artifact64Downloaded = $False - } - If ($artifact64Downloaded) { - md ldc-multilib > $null - cd ldc-multilib - 7z x ..\LDC-master-x64.7z > $null - ren lib lib64 - copy ..\ldc-x86\lib -Recurse - ren lib lib32 - (gc etc\ldc2.conf).replace('%%ldcbinarypath%%/../lib', '%%ldcbinarypath%%/../lib64') | sc etc\ldc2.conf - $conf32 = gc ..\ldc-x86\etc\ldc2.conf -Raw - $conf32 = "`r`ni686-pc-windows-msvc:" + $conf32.Substring($conf32.IndexOf("`r`ndefault:") + 10) - $conf32 = $conf32.Replace('%%ldcbinarypath%%/../lib', '%%ldcbinarypath%%/../lib32') - ac etc\ldc2.conf $conf32 - $artifactFilename = "LDC-master-$Env:APPVEYOR_BUILD_NUMBER-multilib.7z" - 7z a "..\$artifactFilename" * > $null - cd .. - Push-AppveyorArtifact $artifactFilename - } - } - #---------------------------------# # test configuration # #---------------------------------# @@ -187,25 +149,112 @@ # deployment configuration # #---------------------------------# +after_test: + # Install LDC + - ps: | + cd c:\projects\ninja-ldc + $ldcInstallDir = "c:\projects\ldc2-$Env:APPVEYOR_JOB_ARCH" + ninja install > $null + cd "$ldcInstallDir" + (cat etc\ldc2.conf).replace("C:/projects/ldc2-$Env:APPVEYOR_JOB_ARCH/", '%%ldcbinarypath%%/../') | Set-Content etc\ldc2.conf + cd .. + cp ldc/LICENSE "$ldcInstallDir" + git clone https://github.com/ldc-developers/ldc-scripts.git + cp ldc-scripts\ldc2-packaging\pkgfiles\README.txt "$ldcInstallDir" + # Build dub + - ps: | + cd c:\projects + $ldcInstallDir = "c:\projects\ldc2-$Env:APPVEYOR_JOB_ARCH" + Set-Item -path env:DC -value "$ldcInstallDir\bin\ldmd2" + git clone --recursive https://github.com/dlang/dub.git + cd dub + git checkout $Env:DUB_VERSION + (cat build.cmd).replace('curl.lib', "$ldcInstallDir\lib\curl.lib") | Set-Content build.cmd + .\build.cmd + cp bin\dub.exe "$ldcInstallDir\bin" + # Build dlang tools + - ps: | + cd c:\projects + $ldcInstallDir = "c:\projects\ldc2-$Env:APPVEYOR_JOB_ARCH" + git clone --recursive https://github.com/dlang/tools.git + cd tools + & "$ldcInstallDir\bin\ldmd2" -w rdmd.d + & "$ldcInstallDir\bin\ldmd2" -w ddemangle.d + & "$ldcInstallDir\bin\ldmd2" -w DustMite\dustmite.d DustMite\splitter.d + cp *.exe "$ldcInstallDir\bin" + # Pack installation dir & publish as artifact + - ps: | + cd c:\projects + If (Test-Path Env:APPVEYOR_REPO_TAG_NAME) { + $artifactBasename = "ldc2-$($Env:APPVEYOR_REPO_TAG_NAME.Substring(1))-windows-$Env:APPVEYOR_JOB_ARCH" + } Else { + $artifactBasename = "ldc2-$($Env:APPVEYOR_REPO_COMMIT.Substring(0, 8))-windows-$Env:APPVEYOR_JOB_ARCH" + } + ren "ldc2-$Env:APPVEYOR_JOB_ARCH" $artifactBasename + 7z a -mx=9 "$artifactBasename.7z" $artifactBasename > $null + ren $artifactBasename "ldc2-$Env:APPVEYOR_JOB_ARCH" + Push-AppveyorArtifact "$artifactBasename.7z" + # x86 job: Create a 32/64-bit multilib artifact if the commit is on the master branch + # (or a tag). It consists of the x64 artifact (published by a successful x64 job) + # downloaded from GitHub, augmented by the 32-bit libs and an extra section in the + # ldc2.conf file for `-m32` (using the lib32 directory). + - ps: | + If (($Env:APPVEYOR_JOB_ARCH -eq 'x86') -And + ( (Test-Path Env:APPVEYOR_REPO_TAG_NAME) -Or + ( ($Env:APPVEYOR_REPO_BRANCH -eq 'master') -And !(Test-Path Env:APPVEYOR_PULL_REQUEST_NUMBER) ) ) ) { + echo 'Preparing 32/64-bit multilib artifact...' + cd c:\projects + If (Test-Path Env:APPVEYOR_REPO_TAG_NAME) { + $artifact64 = "https://github.com/ldc-developers/ldc/releases/download/$Env:APPVEYOR_REPO_TAG_NAME/ldc2-$($Env:APPVEYOR_REPO_TAG_NAME.Substring(1))-windows-x64.7z" + $artifactBasename = "ldc2-$($Env:APPVEYOR_REPO_TAG_NAME.Substring(1))-windows" + } Else { + $artifact64 = "https://github.com/ldc-developers/ldc/releases/download/CI/ldc2-$($Env:APPVEYOR_REPO_COMMIT.Substring(0, 8))-windows-x64.7z" + $artifactBasename = "ldc2-$($Env:APPVEYOR_REPO_COMMIT.Substring(0, 8))-windows" + } + $artifact64Downloaded = $True + Try { + (New-Object Net.WebClient).DownloadFile("$artifact64", 'c:\projects\ldc2-x64.7z') + } Catch { + echo 'Failed to download the 64-bit artifact from GitHub (the x64 job probably failed).' + echo 'Skipping the 32/64-bit multilib artifact.' + $artifact64Downloaded = $False + } + If ($artifact64Downloaded) { + 7z x ldc2-x64.7z > $null + del ldc2-x64.7z + ren "$artifactBasename-x64" "$artifactBasename-multilib" + cd "$artifactBasename-multilib" + ren lib lib64 + copy ..\ldc2-x86\lib -Recurse + ren lib lib32 + (cat etc\ldc2.conf).replace('%%ldcbinarypath%%/../lib', '%%ldcbinarypath%%/../lib64') | Set-Content etc\ldc2.conf + $conf32 = cat ..\ldc2-x86\etc\ldc2.conf -Raw + $conf32 = "`r`ni686-pc-windows-msvc:" + $conf32.Substring($conf32.IndexOf("`r`ndefault:") + 10) + $conf32 = $conf32.Replace('%%ldcbinarypath%%/../lib', '%%ldcbinarypath%%/../lib32') + Add-Content etc\ldc2.conf $conf32 + cd .. + 7z a -mx=9 "$artifactBasename-multilib.7z" "$artifactBasename-multilib" > $null + Push-AppveyorArtifact "$artifactBasename-multilib.7z" + } + } + deploy: - - provider: GitHub - release: 'LDC Win64 master' - description: "Latest successful Windows CI builds of branch 'master'" - draft: true + - release: CI prerelease: true + provider: GitHub auth_token: secure: qnbD8agL9mr0SFvy/sMkR2E29oQQ427T5zYwVVZkjRS3IZ361tG+9jlSiyEkyULy - artifact: LDC-master-$(APPVEYOR_BUILD_NUMBER)-$(APPVEYOR_JOB_ARCH).7z + artifact: /ldc2-.*\.7z/ on: branch: master - - provider: GitHub - release: 'LDC Win64 master' - description: "Latest successful Windows CI builds of branch 'master'" - draft: true + appveyor_repo_tag: false + - release: $(APPVEYOR_REPO_TAG_NAME) + description: $(APPVEYOR_REPO_TAG_NAME) prerelease: true + draft: true + provider: GitHub auth_token: secure: qnbD8agL9mr0SFvy/sMkR2E29oQQ427T5zYwVVZkjRS3IZ361tG+9jlSiyEkyULy - artifact: LDC-master-$(APPVEYOR_BUILD_NUMBER)-multilib.7z + artifact: /ldc2-.*\.7z/ on: - branch: master - APPVEYOR_JOB_ARCH: x86 + appveyor_repo_tag: true diff -Nru ldc-1.6.0/.circleci/config.yml ldc-1.8.0/.circleci/config.yml --- ldc-1.6.0/.circleci/config.yml 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/.circleci/config.yml 2018-03-12 22:13:03.000000000 +0000 @@ -1,93 +1,276 @@ +commonSteps: &commonSteps + steps: + # Each step starts in working dir `/project` (containing the cloned LDC repo). + - run: + name: Install dependencies + command: | + cd .. + if [ "$CI_OS" = "linux" ]; then + export DEBIAN_FRONTEND=noninteractive + dpkg --add-architecture i386 + apt-get -y update + apt-get -yq install software-properties-common + add-apt-repository -y ppa:ubuntu-toolchain-r/test + apt-get -y update + apt-get -yq install curl git-core g++-6-multilib ninja-build gdb python-pip unzip zip libcurl4-openssl-dev libcurl3:i386 + echo "export CC=gcc-6" >> $BASH_ENV + echo "export CXX=g++-6" >> $BASH_ENV + # install CMake + curl -L -o cmake-x64.tar.gz https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.tar.gz + mkdir cmake-x64 + tar -xf cmake-x64.tar.gz --strip 1 -C cmake-x64 + echo "export PATH=$PWD/cmake-x64/bin:$PATH" >> $BASH_ENV + # use ld.gold per default, so that LTO is tested + update-alternatives --install /usr/bin/ld ld /usr/bin/ld.gold 99 + else + # install CMake + curl -L -o cmake-x64.tar.gz https://cmake.org/files/v3.10/cmake-3.10.0-Darwin-x86_64.tar.gz + mkdir cmake-x64 + tar -xf cmake-x64.tar.gz --strip 3 -C cmake-x64 + # install Ninja + curl -OL https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-mac.zip + mkdir ninja + tar -xf ninja-mac.zip -C ninja + echo "export PATH=$PWD/cmake-x64/bin:$PWD/ninja:$PATH" >> $BASH_ENV + # install Python pip + curl -OL https://bootstrap.pypa.io/get-pip.py + python get-pip.py + fi + # install lit + pip install --user lit + - checkout + - run: + name: Checkout git submodules + command: git submodule update --init + - run: + name: Install LDC-flavoured LLVM + command: | + cd .. + mkdir llvm-$LLVM_VERSION + assertsSuffix="" + if [ -z "$CIRCLE_TAG" ]; then + echo "Using LLVM with enabled assertions" + assertsSuffix="-withAsserts" + fi + curl -L -o llvm.tar.xz https://github.com/ldc-developers/llvm/releases/download/ldc-v$LLVM_VERSION/llvm-$LLVM_VERSION-$CI_OS-x86_64$assertsSuffix.tar.xz + tar -xf llvm.tar.xz --strip 1 -C llvm-$LLVM_VERSION + rm llvm.tar.xz + - run: + name: Install LDC host compiler + command: | + cd .. + curl -L -o ldc2.tar.xz https://github.com/ldc-developers/ldc/releases/download/v$HOST_LDC_VERSION/ldc2-$HOST_LDC_VERSION-$CI_OS-x86_64.tar.xz + mkdir ldc2-$HOST_LDC_VERSION + tar -xf ldc2.tar.xz --strip 1 -C ldc2-$HOST_LDC_VERSION + rm ldc2.tar.xz + - run: + name: Build bootstrap LDC + command: | + cd .. + # output versions + cmake --version + ninja --version + if [ "$CI_OS" = "linux" ]; then gdb --version; fi + python -c "import lit; lit.main();" --version | head -n 1 + # build + HOST_LDMD=$PWD/ldc2-$HOST_LDC_VERSION/bin/ldmd2 + mkdir bootstrap + cd bootstrap + cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ROOT_DIR=$PWD/../llvm-$LLVM_VERSION -DBUILD_SHARED_LIBS=OFF -DD_COMPILER=$HOST_LDMD $BOOTSTRAP_CMAKE_FLAGS $CIRCLE_WORKING_DIRECTORY + ninja -j3 + bin/ldc2 -version + cd .. + - run: + name: Build LDC and stdlib unittest runners + command: | + cd .. + LDC_INSTALL_DIR=$PWD/ldc2-x64 + HOST_LDMD=$PWD/bootstrap/bin/ldmd2 + mkdir ninja-ldc + cd ninja-ldc + cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ROOT_DIR=$PWD/../llvm-$LLVM_VERSION -DCMAKE_INSTALL_PREFIX=$LDC_INSTALL_DIR -DINCLUDE_INSTALL_DIR=$LDC_INSTALL_DIR/import -DD_COMPILER=$HOST_LDMD $EXTRA_CMAKE_FLAGS $CIRCLE_WORKING_DIRECTORY + # compiling the std.regex.internal.tests unittests eats large amounts of memory + if [ "$CI_OS" = "linux" ]; then + ninja -j2 all runtime/objects-unittest-debug/std/regex/internal/tests.o runtime/objects-unittest/std/regex/internal/tests.o runtime/objects-unittest-debug_32/std/regex/internal/tests.o runtime/objects-unittest_32/std/regex/internal/tests.o + else + ninja -j2 all runtime/objects-unittest-debug_64/std/regex/internal/tests.o runtime/objects-unittest_64/std/regex/internal/tests.o runtime/objects-unittest-debug_32/std/regex/internal/tests.o runtime/objects-unittest_32/std/regex/internal/tests.o + fi + ninja -j3 all-test-runners + bin/ldc2 -version + cd .. + - run: + name: Build and run LDC D unittests + when: always + command: cd ../ninja-ldc && ctest --output-on-failure -R ldc2-unittest + - run: + name: Run LIT testsuite + when: always + command: cd ../ninja-ldc && ctest -V -R lit-tests + - run: + name: Run DMD testsuite + when: always + command: | + cd ../ninja-ldc + if [ "$CI_OS" = "osx" ]; then + # FIXME: A few 32-bit tests fail due to output containing linker warnings like: + # ld: warning: could not create compact unwind for __D3std11parallelism16submitAndExecuteFCQBlQBk8TaskPoolMDFZvZv: stack subl instruction is too different from dwarf stack size + rm ../project/tests/d2/dmd-testsuite/runnable/{test13613,statictor}.d + else + # Circle's RAM disk FS apparently doesn't allow long paths. + rm ../project/tests/d2/dmd-testsuite/compilable/issue17167.sh + fi + DMD_TESTSUITE_MAKE_ARGS=-j3 ctest -V -R dmd-testsuite + - run: + name: Run stdlib unittests + when: always + command: | + cd ../ninja-ldc + if [ "$CI_OS" = "linux" ]; then + # FIXME: Exclude std.process unittests for now. + # CircleCI doesn't throw an expected ProcessException when spawning a + # process in a working dir with 0400 permissions (no search permissions). + ctest -j3 --output-on-failure -E "std\.process|dmd-testsuite|ldc2-unittest|lit-tests" + else + ctest -j3 --output-on-failure -E "dmd-testsuite|ldc2-unittest|lit-tests" + fi + - run: + name: Install LDC + command: | + cd ../ninja-ldc + ninja install + cd .. + LDC_INSTALL_DIR=$PWD/ldc2-x64 + perl -pi -e s?$LDC_INSTALL_DIR/?%%ldcbinarypath%%/../?g $LDC_INSTALL_DIR/etc/ldc2.conf + cp project/LICENSE $LDC_INSTALL_DIR + git clone https://github.com/ldc-developers/ldc-scripts.git + cp ldc-scripts/ldc2-packaging/pkgfiles/README $LDC_INSTALL_DIR + cp -r ldc-scripts/ldc2-packaging/pkgfiles/dub $LDC_INSTALL_DIR/etc + # Now rename the installation dir to test portability. + NEW_LDC_INSTALL_DIR=$PWD/ldc2-install + mv $LDC_INSTALL_DIR $NEW_LDC_INSTALL_DIR + echo "export LDC_INSTALL_DIR=$NEW_LDC_INSTALL_DIR" >> $BASH_ENV + - run: + name: Hello world integration test with shared libs + command: | + cd .. + altLibSuffix="32" + if [ "$CI_OS" = "osx" ]; then + altLibSuffix="" + fi + echo 'void main() { import std.stdio; writeln("Hello world, ", size_t.sizeof * 8, " bits"); }' > hello.d + $LDC_INSTALL_DIR/bin/ldc2 hello.d -m64 -of=hello64 -link-defaultlib-shared -L-Wl,-rpath,$LDC_INSTALL_DIR/lib + $LDC_INSTALL_DIR/bin/ldc2 hello.d -m32 -of=hello32 -link-defaultlib-shared -L-Wl,-rpath,$LDC_INSTALL_DIR/lib$altLibSuffix + ./hello64 + ./hello32 + - run: + name: Build dub + command: | + cd .. + export DMD=$LDC_INSTALL_DIR/bin/ldmd2 + git clone --recursive https://github.com/dlang/dub.git + cd dub + git checkout $DUB_VERSION + if [ -z "$CIRCLE_TAG" ]; then + # FIXME: dub is built with `-g -O`, which leads to issue #2361 with enabled + # assertions, at least on Linux. So strip `-g` for untagged builds. + perl -pi -e "s? -g -O ? -O ?g" build.sh + fi + ./build.sh + cp bin/dub $LDC_INSTALL_DIR/bin + cd .. + - run: + name: Build dlang tools + command: | + cd .. + git clone --recursive https://github.com/dlang/tools.git + cd tools + make -f posix.mak install DMD=$LDC_INSTALL_DIR/bin/ldmd2 INSTALL_DIR=$PWD + cp bin/{rdmd,ddemangle,dustmite} $LDC_INSTALL_DIR/bin + cd .. + - run: + name: Pack installation dir + command: | + cd .. + mkdir artifacts + if [ -z "$CIRCLE_TAG" ]; then + artifactBasename="ldc2-${CIRCLE_SHA1:0:8}-$CI_OS-x86_64-$(date "+%Y%m%d")" + else + artifactBasename="ldc2-${CIRCLE_TAG:1}-$CI_OS-x86_64" + fi + mv $LDC_INSTALL_DIR $artifactBasename + XZ_OPT=-9 tar -cJf artifacts/$artifactBasename.tar.xz $artifactBasename + - run: + name: Pack source dir + command: | + cd .. + if [ "$CI_OS" = "linux" ]; then + if [ -z "$CIRCLE_TAG" ]; then + artifactBasename="ldc-${CIRCLE_SHA1:0:8}-src" + else + artifactBasename="ldc-${CIRCLE_TAG:1}-src" + fi + GZIP=-9 tar -czf artifacts/$artifactBasename.tar.gz --exclude-vcs --transform=s/project/$artifactBasename/ project + tar -xf artifacts/$artifactBasename.tar.gz + zip -r -9 artifacts/$artifactBasename.zip $artifactBasename + fi + - store_artifacts: + path: ../artifacts + - run: + name: Deploy to GitHub CI release + command: | + cd .. + if [[ -n "$CIRCLE_TAG" || ( "$CIRCLE_BRANCH" = "master" && -z "$CIRCLE_PR_NUMBER" ) ]]; then + if [ "$CI_OS" = "linux" ]; then + curl -L -o github-release.tar.bz2 https://github.com/aktau/github-release/releases/download/v0.7.2/linux-amd64-github-release.tar.bz2 + else + curl -L -o github-release.tar.bz2 https://github.com/aktau/github-release/releases/download/v0.7.2/darwin-amd64-github-release.tar.bz2 + fi + tar -xf github-release.tar.bz2 --strip 3 + cd artifacts + # Note: needs GITHUB_TOKEN environment variable + ../github-release upload --user ldc-developers --repo ldc --tag ${CIRCLE_TAG:-CI} --name "$(ls ldc2-*.tar.xz)" --file ldc2-*.tar.xz + if [[ -n "$CIRCLE_TAG" && "$CI_OS" = "linux" ]]; then + ../github-release upload --user ldc-developers --repo ldc --tag $CIRCLE_TAG --name "$(ls ldc-*-src.tar.gz)" --file ldc-*-src.tar.gz + ../github-release upload --user ldc-developers --repo ldc --tag $CIRCLE_TAG --name "$(ls ldc-*-src.zip)" --file ldc-*-src.zip + fi + fi + version: 2 jobs: - build: + build-linux: + <<: *commonSteps docker: - - image: gcc + - image: ubuntu:14.04 environment: - - LLVM_VERSION: 5.0.0 - - HOST_LDC_VERSION: 1.3.0 - steps: - - checkout - - run: - name: Checkout git submodules - command: git submodule update --init - - run: - name: Install basic dependencies - command: | - apt update - apt install -y software-properties-common cmake ninja-build gdb python-pip unzip - pip install --user lit - # Use ld.gold per default, so that LTO is tested. - update-alternatives --install /usr/bin/ld ld /usr/bin/ld.gold 99 - g++ --version - ld --version - cmake --version - ninja --version - gdb --version - python -c "import lit; lit.main();" --version | head -n 1 - - restore_cache: - keys: - - llvm-5.0.0 - - host-ldc-{{ .Environment.HOST_LDC_VERSION }} - - run: - name: Install LLVM 5.0.0 - command: | - if [[ ! -d llvm-$LLVM_VERSION ]]; then - wget -O llvm-$LLVM_VERSION.tar.xz http://releases.llvm.org/$LLVM_VERSION/clang+llvm-$LLVM_VERSION-linux-x86_64-ubuntu16.04.tar.xz - mkdir llvm-$LLVM_VERSION - tar -xpf llvm-$LLVM_VERSION.tar.xz --strip 1 -C llvm-$LLVM_VERSION - fi - - save_cache: - key: llvm-5.0.0 - paths: - - llvm-5.0.0 - - run: - name: Install LDC host compiler - command: | - if [[ ! -e ldc2-$HOST_LDC_VERSION-linux-x86_64/bin/ldmd2 ]]; then - wget https://github.com/ldc-developers/ldc/releases/download/v$HOST_LDC_VERSION/ldc2-$HOST_LDC_VERSION-linux-x86_64.tar.xz - tar -xf ldc2-$HOST_LDC_VERSION-linux-x86_64.tar.xz - fi - - save_cache: - key: host-ldc-{{ .Environment.HOST_LDC_VERSION }} - paths: - - ldc2-$HOST_LDC_VERSION-linux-x86_64 - - run: - name: Build bootstrap LDC - command: | - export HOST_LDMD=$PWD/ldc2-$HOST_LDC_VERSION-linux-x86_64/bin/ldmd2 - mkdir bootstrap - cd bootstrap - cmake -G Ninja -DLLVM_ROOT_DIR=$PWD/../llvm-$LLVM_VERSION -DBUILD_SHARED_LIBS=OFF -DD_COMPILER=$HOST_LDMD .. - ninja -j3 - bin/ldc2 -version - cd .. - - run: - name: Build LDC and stdlib unittest runners - command: | - export HOST_LDMD=$PWD/bootstrap/bin/ldmd2 - mkdir build - cd build - cmake -G Ninja -DLLVM_ROOT_DIR=$PWD/../llvm-$LLVM_VERSION -DLDC_INSTALL_LTOPLUGIN=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS=ON -DD_COMPILER=$HOST_LDMD .. - ninja -j3 all all-test-runners - bin/ldc2 -version - cd .. - - run: - name: Build and run LDC D unittests - command: cd build && ctest --output-on-failure -R ldc2-unittest - when: always - - run: - name: Run LIT testsuite - command: cd build && ctest -V -R lit-tests - when: always - - run: - name: Run DMD testsuite - command: cd build && DMD_TESTSUITE_MAKE_ARGS=-j3 ctest -V -R dmd-testsuite - when: always - - run: - name: Run stdlib unittests - # FIXME: Exclude std.process unittests for now. - # CircleCI doesn't throw an expected ProcessException when spawning a - # process in a working dir with 0400 permissions (no search permissions). - command: cd build && ctest -j3 --output-on-failure -E "std\.process|dmd-testsuite|ldc2-unittest|lit-tests" - when: always + - CI_OS: linux + - LLVM_VERSION: 5.0.1 + - HOST_LDC_VERSION: 1.6.0 + - EXTRA_CMAKE_FLAGS: "-DMULTILIB=ON -DCMAKE_EXE_LINKER_FLAGS=-static-libstdc++ -DLDC_INSTALL_LTOPLUGIN=ON -DLDC_INSTALL_LLVM_RUNTIME_LIBS=ON" + - DUB_VERSION: v1.7.2 + build-osx: + <<: *commonSteps + macos: + xcode: "9.0" + environment: + - CI_OS: osx + - MACOSX_DEPLOYMENT_TARGET: 10.8 + - USE_LIBCPP: true + - LLVM_VERSION: 5.0.1 + - HOST_LDC_VERSION: 1.6.0 + - BOOTSTRAP_CMAKE_FLAGS: "-DCMAKE_CXX_FLAGS='-stdlib=libc++' -DCMAKE_EXE_LINKER_FLAGS=-lc++" + - EXTRA_CMAKE_FLAGS: "-DMULTILIB=ON -DCMAKE_CXX_FLAGS='-stdlib=libc++' -DCMAKE_EXE_LINKER_FLAGS=-lc++" + - DUB_VERSION: v1.7.2 + +workflows: + version: 2 + build: + jobs: + - build-linux: + # This is required to also trigger the job after pushing a tag. + filters: + tags: + only: /.*/ + - build-osx: + filters: + tags: + only: /.*/ diff -Nru ldc-1.6.0/cmake/Modules/FindLLVM.cmake ldc-1.8.0/cmake/Modules/FindLLVM.cmake --- ldc-1.6.0/cmake/Modules/FindLLVM.cmake 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/cmake/Modules/FindLLVM.cmake 2018-03-12 22:13:03.000000000 +0000 @@ -17,7 +17,8 @@ # llvm-config is searched for in ${LLVM_ROOT_DIR}/bin. # LLVM_VERSION_MAJOR - Major version of LLVM. # LLVM_VERSION_MINOR - Minor version of LLVM. -# LLVM_VERSION_STRING - Full LLVM version string (e.g. 2.9). +# LLVM_VERSION_STRING - Full LLVM version string (e.g. 6.0.0svn). +# LLVM_VERSION_BASE_STRING - Base LLVM version string without git/svn suffix (e.g. 6.0.0). # # Note: The variable names were chosen in conformance with the offical CMake # guidelines, see ${CMAKE_ROOT}/Modules/readme.txt. @@ -105,6 +106,9 @@ llvm_set(ROOT_DIR prefix true) llvm_set(ENABLE_ASSERTIONS assertion-mode) + # The LLVM version string _may_ contain a git/svn suffix, so cut that off + string(SUBSTRING "${LLVM_VERSION_STRING}" 0 5 LLVM_VERSION_BASE_STRING) + if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-8][\\.0-9A-Za-z]*") # Versions below 3.9 do not support components debuginfocodeview, globalisel list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfocodeview" index) @@ -133,6 +137,14 @@ set(LLVM_LIBRARIES "${LLVM_LIBRARIES};-lLLVMTableGen") endif() endif() + + if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-9][\\.0-9A-Za-z]*") + # Versions below 4.0 do not support llvm-config --cmakedir + set(LLVM_CMAKEDIR ${LLVM_LIBRARY_DIRS}/cmake/llvm) + else() + llvm_set(CMAKEDIR cmakedir) + endif() + llvm_set(TARGETS_TO_BUILD targets-built) string(REGEX MATCHALL "${pattern}[^ ]+" LLVM_TARGETS_TO_BUILD ${LLVM_TARGETS_TO_BUILD}) endif() diff -Nru ldc-1.6.0/CMakeLists.txt ldc-1.8.0/CMakeLists.txt --- ldc-1.6.0/CMakeLists.txt 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/CMakeLists.txt 2018-03-12 22:13:03.000000000 +0000 @@ -52,11 +52,11 @@ # # Version information -set(LDC_VERSION "1.6.0") # May be overridden by git hash tag +set(LDC_VERSION "1.8.0") # May be overridden by git hash tag set(DMDFE_MAJOR_VERSION 2) set(DMDFE_MINOR_VERSION 0) -set(DMDFE_PATCH_VERSION 76) -set(DMDFE_FIX_LEVEL 1) # Comment out if not used +set(DMDFE_PATCH_VERSION 78) +set(DMDFE_FIX_LEVEL 3) # Comment out if not used set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}${DMDFE_PATCH_VERSION}) if(DEFINED DMDFE_FIX_LEVEL) @@ -89,7 +89,7 @@ message(FATAL_ERROR "D version 1 is no longer supported. Please consider using D version 2 or checkout the 'd1' git branch for the last version supporting D version 1.") elseif(D_VERSION EQUAL 2) - set(DDMDFE_PATH ddmd) + set(DDMDFE_PATH dmd) set(LDC_EXE ldc2) set(LDMD_EXE ldmd2) set(LDCPROFDATA_EXE ldc-profdata) @@ -190,17 +190,8 @@ append("/GR- /EHs-c-" CMAKE_CXX_FLAGS) append("/D_HAS_EXCEPTIONS=0" CMAKE_CXX_FLAGS) - # warning C4018: signed/unsigned mismatch - # warning C4101: unreferenced local variable - # warning C4102: unreferenced label - # warning C4146: unary minus operator applied to unsigned type, result still unsigned - # warning C4201: nonstandard extension used: nameless struct/union - # warnings C4244 and C4267: conversion from '...' to '...', possible loss of data - # warnings C4456-4459: declaration of '...' hides ... - # warning C4624: destructor was implicitly defined as deleted because a base class destructor is inaccessible or deleted - # warning C4800: forcing value to bool 'true' or 'false' (performance warning) - # warning C4996: we're not using Microsoft's secure stringOp_s() functions - append("/wd4018 /wd4101 /wd4102 /wd4146 /wd4201 /wd4244 /wd4267 /wd4456 /wd4457 /wd4458 /wd4459 /wd4624 /wd4800 /wd4996" LDC_CXXFLAGS) + # disable warning C4201: nonstandard extension used: nameless struct/union + append("/wd4201" LDC_CXXFLAGS) endif() # Append -mminimal-toc for gcc 4.0.x - 4.5.x on ppc64 if( CMAKE_COMPILER_IS_GNUCXX @@ -306,6 +297,7 @@ set(DRV_SRC driver/cache.cpp driver/cl_options.cpp + driver/cl_options_instrumentation.cpp driver/cl_options_sanitizers.cpp driver/cl_options-llvm.cpp driver/codegenerator.cpp @@ -320,12 +312,14 @@ driver/linker-gcc.cpp driver/linker-msvc.cpp driver/main.cpp + driver/plugins.cpp ${CMAKE_BINARY_DIR}/driver/ldc-version.cpp ) set(DRV_HDR driver/cache.h driver/cache_pruning.h driver/cl_options.h + driver/cl_options_instrumentation.h driver/cl_options_sanitizers.h driver/cl_options-llvm.h driver/codegenerator.h @@ -335,6 +329,7 @@ driver/ldc-version.h driver/archiver.h driver/linker.h + driver/plugins.h driver/targetmachine.h driver/toobj.h driver/tool.h @@ -376,21 +371,17 @@ include(HandleLTOPGOBuildOptions) # -# Enable PGO if supported for this platform. -# -set(LDC_WITH_PGO True) # must be a valid Python boolean constant (case sensitive) -message(STATUS "Building LDC with PGO support") -append("-DLDC_WITH_PGO" LDC_CXXFLAGS) - -# # Enable Dynamic compilation if supported for this platform and LLVM version. -# LLVM >= 3.9 is required # -set(LDC_DYNAMIC_COMPILE False) # must be a valid Python boolean constant (case sensitive) -if (NOT (LDC_LLVM_VER LESS 400)) - message(STATUS "Building LDC with dynamic compilation support") - add_definitions(-DLDC_DYNAMIC_COMPILE) - set(LDC_DYNAMIC_COMPILE True) +set(LDC_DYNAMIC_COMPILE "AUTO" CACHE STRING "Support dynamic compilation (True|False). Enabled by default.") +if(LDC_DYNAMIC_COMPILE STREQUAL "AUTO") + set(LDC_DYNAMIC_COMPILE False) # must be a valid Python boolean constant (case sensitive) + if (NOT (LDC_LLVM_VER LESS 500)) + set(LDC_DYNAMIC_COMPILE True) + message(STATUS "Building LDC with dynamic compilation support") + add_definitions(-DLDC_DYNAMIC_COMPILE) + add_definitions(-DLDC_DYNAMIC_COMPILE_API_VERSION=1) + endif() endif() # @@ -560,6 +551,24 @@ endif() endif() +# Plugin support +if(UNIX) + set(LDC_ENABLE_PLUGINS_DEFAULT ON) +else() + set(LDC_ENABLE_PLUGINS_DEFAULT OFF) +endif() +set(LDC_ENABLE_PLUGINS ${LDC_ENABLE_PLUGINS_DEFAULT} CACHE BOOL "Build LDC with plugin support (increases binary size)") +if(LDC_ENABLE_PLUGINS) + message(STATUS "Building LDC with plugin support (LDC_ENABLE_PLUGINS=ON)") + add_definitions(-DLDC_ENABLE_PLUGINS) + # For plugin support, we need to link with --export-dynamic on Unix. + if(UNIX AND NOT APPLE) + set(LDC_LINKERFLAG_LIST "${LDC_LINKERFLAG_LIST};-Wl,--export-dynamic") + endif() +else() + message(STATUS "Building LDC without plugin support (LDC_ENABLE_PLUGINS=OFF)") +endif() + set(LDC_LINK_MANUALLY OFF) if(UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"))) # On Unix-like systems, DMD and LDC will use the C compiler for linking, but @@ -737,19 +746,17 @@ endif() # -# Locate ASan and other runtime libraries, and copy them to our lib folder +# Locate ASan and other LLVM compiler-rt libraries, and copy them to our lib folder # Location is LLVM_LIBRARY_DIRS/clang//lib// , for example LLVM_LIBRARY_DIRS/clang/4.0.0/lib/darwin/ # -if(APPLE) +if(APPLE OR WIN32) set(LDC_INSTALL_LLVM_RUNTIME_LIBS_DEFAULT ON) else() set(LDC_INSTALL_LLVM_RUNTIME_LIBS_DEFAULT OFF) endif() -set(LDC_INSTALL_LLVM_RUNTIME_LIBS ${LDC_INSTALL_LLVM_RUNTIME_LIBS_DEFAULT} CACHE BOOL "Copy/install runtime libraries (ASan, libFuzzer) from LLVM/Clang into LDC lib dir when available.") +set(LDC_INSTALL_LLVM_RUNTIME_LIBS ${LDC_INSTALL_LLVM_RUNTIME_LIBS_DEFAULT} CACHE BOOL "Copy/install LLVM compiler-rt libraries (ASan, libFuzzer, ...) from LLVM/Clang into LDC lib dir when available.") function(copy_compilerrt_lib llvm_lib_name ldc_lib_name fixup_dylib) - # The LLVM version string can contain the SVN revision number, so cut that off - string(SUBSTRING "${LLVM_VERSION_STRING}" 0 5 LLVM_VERSION_STRING_CROPPED) - set(llvm_lib_path ${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_STRING_CROPPED}/lib/${llvm_lib_name}) + set(llvm_lib_path ${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_BASE_STRING}/lib/${llvm_lib_name}) if(EXISTS ${llvm_lib_path}) message(STATUS "Copying runtime library: ${llvm_lib_path} --> ${ldc_lib_name}") set(ldc_lib_path ${PROJECT_BINARY_DIR}/lib${LIB_SUFFIX}/${ldc_lib_name}) @@ -762,20 +769,42 @@ message(STATUS "Not found: ${llvm_lib_path}") endif() endfunction() +include(CheckTypeSize) +check_type_size(void* ptr_size) if (LDC_INSTALL_LLVM_RUNTIME_LIBS) # Locate LLVM sanitizer runtime libraries, and copy them to our lib folder # Note: libFuzzer is part of compiler-rt version >= 6.0, but was part of LLVM =< 5.0 if(APPLE) copy_compilerrt_lib("darwin/libclang_rt.asan_osx_dynamic.dylib" "libldc_rt.asan_osx_dynamic.dylib" TRUE) + copy_compilerrt_lib("darwin/libclang_rt.osx.a" "libldc_rt.osx.a" FALSE) + copy_compilerrt_lib("darwin/libclang_rt.profile_osx.a" "libldc_rt.profile_osx.a" FALSE) if(NOT (LDC_LLVM_VER LESS 600)) copy_compilerrt_lib("darwin/libclang_rt.fuzzer_osx.a" "libldc_rt.fuzzer_osx.a" FALSE) + copy_compilerrt_lib("darwin/libclang_rt.xray_osx.a" "libldc_rt.xray_osx.a" FALSE) endif() elseif(UNIX) - copy_compilerrt_lib("linux/libclang_rt.asan-x86_64.a" "libldc_rt.asan-x86_64.a" FALSE) + copy_compilerrt_lib("linux/libclang_rt.asan-x86_64.a" "libldc_rt.asan-x86_64.a" FALSE) + copy_compilerrt_lib("linux/libclang_rt.builtins-x86_64.a" "libldc_rt.builtins-x86_64.a" FALSE) + copy_compilerrt_lib("linux/libclang_rt.profile-x86_64.a" "libldc_rt.profile-x86_64.a" FALSE) + if(NOT (LDC_LLVM_VER LESS 500)) + copy_compilerrt_lib("linux/libclang_rt.xray-x86_64.a" "libldc_rt.xray-x86_64.a" FALSE) + endif() if(NOT (LDC_LLVM_VER LESS 600)) copy_compilerrt_lib("linux/libclang_rt.fuzzer-x86_64.a" "libldc_rt.fuzzer-x86_64.a" FALSE) endif() + elseif(WIN32) + set(compilerrt_arch_suffix "x86_64") + if(${ptr_size} EQUAL 4) + set(compilerrt_arch_suffix "i386") + endif() + copy_compilerrt_lib("windows/clang_rt.asan-${compilerrt_arch_suffix}.lib" "ldc_rt.asan.lib" FALSE) + copy_compilerrt_lib("windows/clang_rt.builtins-${compilerrt_arch_suffix}.lib" "ldc_rt.builtins.lib" FALSE) + copy_compilerrt_lib("windows/clang_rt.profile-${compilerrt_arch_suffix}.lib" "ldc_rt.profile.lib" FALSE) + if(NOT (LDC_LLVM_VER LESS 600)) + copy_compilerrt_lib("windows/clang_rt.fuzzer-${compilerrt_arch_suffix}.lib" "ldc_rt.fuzzer.lib" FALSE) + copy_compilerrt_lib("windows/clang_rt.xray-${compilerrt_arch_suffix}.lib" "ldc_rt.xray.lib" FALSE) + endif() endif() if(LDC_LLVM_VER LESS 600) diff -Nru ldc-1.6.0/ddmd/access.d ldc-1.8.0/ddmd/access.d --- ldc-1.6.0/ddmd/access.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/access.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,605 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/access.d, _access.d) - */ - -module ddmd.access; - -// Online documentation: https://dlang.org/phobos/ddmd_access.html - -import ddmd.aggregate; -import ddmd.dclass; -import ddmd.declaration; -import ddmd.dmodule; -import ddmd.dscope; -import ddmd.dstruct; -import ddmd.dsymbol; -import ddmd.errors; -import ddmd.expression; -import ddmd.func; -import ddmd.globals; -import ddmd.mtype; -import ddmd.tokens; - -private enum LOG = false; - -/**************************************** - * Return Prot access for Dsymbol smember in this declaration. - */ -extern (C++) Prot getAccess(AggregateDeclaration ad, Dsymbol smember) -{ - Prot access_ret = Prot(PROTnone); - static if (LOG) - { - printf("+AggregateDeclaration::getAccess(this = '%s', smember = '%s')\n", ad.toChars(), smember.toChars()); - } - assert(ad.isStructDeclaration() || ad.isClassDeclaration()); - if (smember.toParent() == ad) - { - access_ret = smember.prot(); - } - else if (smember.isDeclaration().isStatic()) - { - access_ret = smember.prot(); - } - if (ClassDeclaration cd = ad.isClassDeclaration()) - { - for (size_t i = 0; i < cd.baseclasses.dim; i++) - { - BaseClass* b = (*cd.baseclasses)[i]; - Prot access = getAccess(b.sym, smember); - switch (access.kind) - { - case PROTnone: - break; - case PROTprivate: - access_ret = Prot(PROTnone); // private members of base class not accessible - break; - case PROTpackage: - case PROTprotected: - case PROTpublic: - case PROTexport: - // If access is to be tightened - if (PROTpublic < access.kind) - access = Prot(PROTpublic); - // Pick path with loosest access - if (access_ret.isMoreRestrictiveThan(access)) - access_ret = access; - break; - default: - assert(0); - } - } - } - static if (LOG) - { - printf("-AggregateDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", ad.toChars(), smember.toChars(), access_ret); - } - return access_ret; -} - -/******************************************************** - * Helper function for checkAccess() - * Returns: - * false is not accessible - * true is accessible - */ -extern (C++) static bool isAccessible(Dsymbol smember, Dsymbol sfunc, AggregateDeclaration dthis, AggregateDeclaration cdscope) -{ - assert(dthis); - version (none) - { - printf("isAccessible for %s.%s in function %s() in scope %s\n", dthis.toChars(), smember.toChars(), sfunc ? sfunc.toChars() : "NULL", cdscope ? cdscope.toChars() : "NULL"); - } - if (hasPrivateAccess(dthis, sfunc) || isFriendOf(dthis, cdscope)) - { - if (smember.toParent() == dthis) - return true; - if (ClassDeclaration cdthis = dthis.isClassDeclaration()) - { - for (size_t i = 0; i < cdthis.baseclasses.dim; i++) - { - BaseClass* b = (*cdthis.baseclasses)[i]; - Prot access = getAccess(b.sym, smember); - if (access.kind >= PROTprotected || isAccessible(smember, sfunc, b.sym, cdscope)) - { - return true; - } - } - } - } - else - { - if (smember.toParent() != dthis) - { - if (ClassDeclaration cdthis = dthis.isClassDeclaration()) - { - for (size_t i = 0; i < cdthis.baseclasses.dim; i++) - { - BaseClass* b = (*cdthis.baseclasses)[i]; - if (isAccessible(smember, sfunc, b.sym, cdscope)) - return true; - } - } - } - } - return false; -} - -/******************************* - * Do access check for member of this class, this class being the - * type of the 'this' pointer used to access smember. - * Returns true if the member is not accessible. - */ -extern (C++) bool checkAccess(AggregateDeclaration ad, Loc loc, Scope* sc, Dsymbol smember) -{ - FuncDeclaration f = sc.func; - AggregateDeclaration cdscope = sc.getStructClassScope(); - static if (LOG) - { - printf("AggregateDeclaration::checkAccess() for %s.%s in function %s() in scope %s\n", ad.toChars(), smember.toChars(), f ? f.toChars() : null, cdscope ? cdscope.toChars() : null); - } - Dsymbol smemberparent = smember.toParent(); - if (!smemberparent || !smemberparent.isAggregateDeclaration()) - { - static if (LOG) - { - printf("not an aggregate member\n"); - } - return false; // then it is accessible - } - // BUG: should enable this check - //assert(smember.parent.isBaseOf(this, NULL)); - bool result; - Prot access; - if (smemberparent == ad) - { - access = smember.prot(); - result = access.kind >= PROTpublic || hasPrivateAccess(ad, f) || isFriendOf(ad, cdscope) || (access.kind == PROTpackage && hasPackageAccess(sc, smember)) || ad.getAccessModule() == sc._module; - static if (LOG) - { - printf("result1 = %d\n", result); - } - } - else if ((access = getAccess(ad, smember)).kind >= PROTpublic) - { - result = true; - static if (LOG) - { - printf("result2 = %d\n", result); - } - } - else if (access.kind == PROTpackage && hasPackageAccess(sc, ad)) - { - result = true; - static if (LOG) - { - printf("result3 = %d\n", result); - } - } - else - { - result = isAccessible(smember, f, ad, cdscope); - static if (LOG) - { - printf("result4 = %d\n", result); - } - } - if (!result) - { - ad.error(loc, "member `%s` is not accessible", smember.toChars()); - //printf("smember = %s %s, prot = %d, semanticRun = %d\n", - // smember.kind(), smember.toPrettyChars(), smember.prot(), smember.semanticRun); - return true; - } - return false; -} - -/**************************************** - * Determine if this is the same or friend of cd. - */ -extern (C++) bool isFriendOf(AggregateDeclaration ad, AggregateDeclaration cd) -{ - static if (LOG) - { - printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", ad.toChars(), cd ? cd.toChars() : "null"); - } - if (ad == cd) - return true; - // Friends if both are in the same module - //if (toParent() == cd.toParent()) - if (cd && ad.getAccessModule() == cd.getAccessModule()) - { - static if (LOG) - { - printf("\tin same module\n"); - } - return true; - } - static if (LOG) - { - printf("\tnot friend\n"); - } - return false; -} - -/**************************************** - * Determine if scope sc has package level access to s. - */ -extern (C++) bool hasPackageAccess(Scope* sc, Dsymbol s) -{ - return hasPackageAccess(sc._module, s); -} - -extern (C++) bool hasPackageAccess(Module mod, Dsymbol s) -{ - static if (LOG) - { - printf("hasPackageAccess(s = '%s', mod = '%s', s.protection.pkg = '%s')\n", s.toChars(), mod.toChars(), s.prot().pkg ? s.prot().pkg.toChars() : "NULL"); - } - Package pkg = null; - if (s.prot().pkg) - pkg = s.prot().pkg; - else - { - // no explicit package for protection, inferring most qualified one - for (; s; s = s.parent) - { - if (Module m = s.isModule()) - { - DsymbolTable dst = Package.resolve(m.md ? m.md.packages : null, null, null); - assert(dst); - Dsymbol s2 = dst.lookup(m.ident); - assert(s2); - Package p = s2.isPackage(); - if (p && p.isPackageMod()) - { - pkg = p; - break; - } - } - else if ((pkg = s.isPackage()) !is null) - break; - } - } - static if (LOG) - { - if (pkg) - printf("\tsymbol access binds to package '%s'\n", pkg.toChars()); - } - if (pkg) - { - if (pkg == mod.parent) - { - static if (LOG) - { - printf("\tsc is in permitted package for s\n"); - } - return true; - } - if (pkg.isPackageMod() == mod) - { - static if (LOG) - { - printf("\ts is in same package.d module as sc\n"); - } - return true; - } - Dsymbol ancestor = mod.parent; - for (; ancestor; ancestor = ancestor.parent) - { - if (ancestor == pkg) - { - static if (LOG) - { - printf("\tsc is in permitted ancestor package for s\n"); - } - return true; - } - } - } - static if (LOG) - { - printf("\tno package access\n"); - } - return false; -} - -/**************************************** - * Determine if scope sc has protected level access to cd. - */ -bool hasProtectedAccess(Scope *sc, Dsymbol s) -{ - if (auto cd = s.isClassMember()) // also includes interfaces - { - for (auto scx = sc; scx; scx = scx.enclosing) - { - if (!scx.scopesym) - continue; - auto cd2 = scx.scopesym.isClassDeclaration(); - if (cd2 && cd.isBaseOf(cd2, null)) - return true; - } - } - return sc._module == s.getAccessModule(); -} - -/********************************** - * Determine if smember has access to private members of this declaration. - */ -extern (C++) bool hasPrivateAccess(AggregateDeclaration ad, Dsymbol smember) -{ - if (smember) - { - AggregateDeclaration cd = null; - Dsymbol smemberparent = smember.toParent(); - if (smemberparent) - cd = smemberparent.isAggregateDeclaration(); - static if (LOG) - { - printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", ad.toChars(), smember.toChars()); - } - if (ad == cd) // smember is a member of this class - { - static if (LOG) - { - printf("\tyes 1\n"); - } - return true; // so we get private access - } - // If both are members of the same module, grant access - while (1) - { - Dsymbol sp = smember.toParent(); - if (sp.isFuncDeclaration() && smember.isFuncDeclaration()) - smember = sp; - else - break; - } - if (!cd && ad.toParent() == smember.toParent()) - { - static if (LOG) - { - printf("\tyes 2\n"); - } - return true; - } - if (!cd && ad.getAccessModule() == smember.getAccessModule()) - { - static if (LOG) - { - printf("\tyes 3\n"); - } - return true; - } - } - static if (LOG) - { - printf("\tno\n"); - } - return false; -} - -/**************************************** - * Check access to d for expression e.d - * Returns true if the declaration is not accessible. - */ -extern (C++) bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d) -{ - if (sc.flags & SCOPEnoaccesscheck) - return false; - static if (LOG) - { - if (e) - { - printf("checkAccess(%s . %s)\n", e.toChars(), d.toChars()); - printf("\te.type = %s\n", e.type.toChars()); - } - else - { - printf("checkAccess(%s)\n", d.toPrettyChars()); - } - } - if (d.isUnitTestDeclaration()) - { - // Unittests are always accessible. - return false; - } - if (!e) - { - if (d.prot().kind == PROTprivate && d.getAccessModule() != sc._module || d.prot().kind == PROTpackage && !hasPackageAccess(sc, d)) - { - error(loc, "%s `%s` is not accessible from module `%s`", d.kind(), d.toPrettyChars(), sc._module.toChars()); - return true; - } - } - else if (e.type.ty == Tclass) - { - // Do access check - ClassDeclaration cd = (cast(TypeClass)e.type).sym; - if (e.op == TOKsuper) - { - ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration(); - if (cd2) - cd = cd2; - } - return checkAccess(cd, loc, sc, d); - } - else if (e.type.ty == Tstruct) - { - // Do access check - StructDeclaration cd = (cast(TypeStruct)e.type).sym; - return checkAccess(cd, loc, sc, d); - } - return false; -} - -/**************************************** - * Check access to package/module `p` from scope `sc`. - * - * Params: - * loc = source location for issued error message - * sc = scope from which to access to a fully qualified package name - * p = the package/module to check access for - * Returns: true if the package is not accessible. - * - * Because a global symbol table tree is used for imported packages/modules, - * access to them needs to be checked based on the imports in the scope chain - * (see https://issues.dlang.org/show_bug.cgi?id=313). - * - */ -extern (C++) bool checkAccess(Loc loc, Scope* sc, Package p) -{ - if (sc._module == p) - return false; - for (; sc; sc = sc.enclosing) - { - if (sc.scopesym && sc.scopesym.isPackageAccessible(p, Prot(PROTprivate))) - return false; - } - auto name = p.toPrettyChars(); - if (p.isPkgMod == PKGmodule || p.isModule()) - deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", p.kind(), name, name); - else - deprecation(loc, "%s %s is not accessible here", p.kind(), name); - return true; -} - -/** - * Check whether symbols `s` is visible in `mod`. - * - * Params: - * mod = lookup origin - * s = symbol to check for visibility - * Returns: true if s is visible in mod - */ -extern (C++) bool symbolIsVisible(Module mod, Dsymbol s) -{ - // should sort overloads by ascending protection instead of iterating here - s = mostVisibleOverload(s); - final switch (s.prot().kind) - { - case PROTundefined: return true; - case PROTnone: return false; // no access - case PROTprivate: return s.getAccessModule() == mod; - case PROTpackage: return s.getAccessModule() == mod || hasPackageAccess(mod, s); - case PROTprotected: return s.getAccessModule() == mod; - case PROTpublic, PROTexport: return true; - } -} - -/** - * Same as above, but determines the lookup module from symbols `origin`. - */ -extern (C++) bool symbolIsVisible(Dsymbol origin, Dsymbol s) -{ - return symbolIsVisible(origin.getAccessModule(), s); -} - -/** - * Same as above but also checks for protected symbols visible from scope `sc`. - * Used for qualified name lookup. - * - * Params: - * sc = lookup scope - * s = symbol to check for visibility - * Returns: true if s is visible by origin - */ -extern (C++) bool symbolIsVisible(Scope *sc, Dsymbol s) -{ - s = mostVisibleOverload(s); - final switch (s.prot().kind) - { - case PROTundefined: return true; - case PROTnone: return false; // no access - case PROTprivate: return sc._module == s.getAccessModule(); - case PROTpackage: return sc._module == s.getAccessModule() || hasPackageAccess(sc._module, s); - case PROTprotected: return hasProtectedAccess(sc, s); - case PROTpublic, PROTexport: return true; - } -} - -/** - * Use the most visible overload to check visibility. Later perform an access - * check on the resolved overload. This function is similar to overloadApply, - * but doesn't recurse nor resolve aliases because protection/visibility is an - * attribute of the alias not the aliasee. - */ -private Dsymbol mostVisibleOverload(Dsymbol s) -{ - if (!s.isOverloadable()) - return s; - - Dsymbol next, fstart = s, mostVisible = s; - for (; s; s = next) - { - // void func() {} - // private void func(int) {} - if (auto fd = s.isFuncDeclaration()) - next = fd.overnext; - // template temp(T) {} - // private template temp(T:int) {} - else if (auto td = s.isTemplateDeclaration()) - next = td.overnext; - // alias common = mod1.func1; - // alias common = mod2.func2; - else if (auto fa = s.isFuncAliasDeclaration()) - next = fa.overnext; - // alias common = mod1.templ1; - // alias common = mod2.templ2; - else if (auto od = s.isOverDeclaration()) - next = od.overnext; - // alias name = sym; - // private void name(int) {} - else if (auto ad = s.isAliasDeclaration()) - { - assert(ad.isOverloadable, "Non overloadable Aliasee in overload list"); - // Yet unresolved aliases store overloads in overnext. - if (ad.semanticRun < PASSsemanticdone) - next = ad.overnext; - else - { - /* This is a bit messy due to the complicated implementation of - * alias. Aliases aren't overloadable themselves, but if their - * Aliasee is overloadable they can be converted to an overloadable - * alias. - * - * This is done by replacing the Aliasee w/ FuncAliasDeclaration - * (for functions) or OverDeclaration (for templates) which are - * simply overloadable aliases w/ weird names. - * - * Usually aliases should not be resolved for visibility checking - * b/c public aliases to private symbols are public. But for the - * overloadable alias situation, the Alias (_ad_) has been moved - * into it's own Aliasee, leaving a shell that we peel away here. - */ - auto aliasee = ad.toAlias(); - if (aliasee.isFuncAliasDeclaration || aliasee.isOverDeclaration) - next = aliasee; - else - { - /* A simple alias can be at the end of a function or template overload chain. - * It can't have further overloads b/c it would have been - * converted to an overloadable alias. - */ - assert(ad.overnext is null, "Unresolved overload of alias"); - break; - } - } - // handled by ddmd.func.overloadApply for unknown reason - assert(next !is ad); // should not alias itself - assert(next !is fstart); // should not alias the overload list itself - } - else - break; - - if (next && mostVisible.prot().isMoreRestrictiveThan(next.prot())) - mostVisible = next; - } - return mostVisible; -} diff -Nru ldc-1.6.0/ddmd/aggregate.d ldc-1.8.0/ddmd/aggregate.d --- ldc-1.6.0/ddmd/aggregate.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/aggregate.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,824 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/aggregate.d, _aggregate.d) - */ - -module ddmd.aggregate; - -// Online documentation: https://dlang.org/phobos/ddmd_aggregate.html - -import core.stdc.stdio; -import core.checkedint; - -import ddmd.arraytypes; -import ddmd.gluelayer; -import ddmd.declaration; -import ddmd.dscope; -import ddmd.dstruct; -import ddmd.dsymbol; -import ddmd.dtemplate; -import ddmd.errors; -import ddmd.expression; -import ddmd.expressionsem; -import ddmd.func; -import ddmd.globals; -import ddmd.id; -import ddmd.identifier; -import ddmd.mtype; -import ddmd.tokens; -import ddmd.visitor; - -enum Sizeok : int -{ - SIZEOKnone, // size of aggregate is not yet able to compute - SIZEOKfwd, // size of aggregate is ready to compute - SIZEOKdone, // size of aggregate is set correctly -} - -alias SIZEOKnone = Sizeok.SIZEOKnone; -alias SIZEOKdone = Sizeok.SIZEOKdone; -alias SIZEOKfwd = Sizeok.SIZEOKfwd; - -enum Baseok : int -{ - BASEOKnone, // base classes not computed yet - BASEOKin, // in process of resolving base classes - BASEOKdone, // all base classes are resolved - BASEOKsemanticdone, // all base classes semantic done -} - -alias BASEOKnone = Baseok.BASEOKnone; -alias BASEOKin = Baseok.BASEOKin; -alias BASEOKdone = Baseok.BASEOKdone; -alias BASEOKsemanticdone = Baseok.BASEOKsemanticdone; - -/*********************************************************** - */ -extern (C++) abstract class AggregateDeclaration : ScopeDsymbol -{ - Type type; - StorageClass storage_class; - Prot protection; - uint structsize; // size of struct - uint alignsize; // size of struct for alignment purposes - VarDeclarations fields; // VarDeclaration fields - Sizeok sizeok; // set when structsize contains valid data - Dsymbol deferred; // any deferred semantic2() or semantic3() symbol - bool isdeprecated; // true if deprecated - - /* !=null if is nested - * pointing to the dsymbol that directly enclosing it. - * 1. The function that enclosing it (nested struct and class) - * 2. The class that enclosing it (nested class only) - * 3. If enclosing aggregate is template, its enclosing dsymbol. - * See AggregateDeclaraton::makeNested for the details. - */ - Dsymbol enclosing; - - VarDeclaration vthis; // 'this' parameter if this aggregate is nested - - // Special member functions - FuncDeclarations invs; // Array of invariants - FuncDeclaration inv; // invariant - NewDeclaration aggNew; // allocator - DeleteDeclaration aggDelete; // deallocator - - // CtorDeclaration or TemplateDeclaration - Dsymbol ctor; - - // default constructor - should have no arguments, because - // it would be stored in TypeInfo_Class.defaultConstructor - CtorDeclaration defaultCtor; - - Dsymbol aliasthis; // forward unresolved lookups to aliasthis - bool noDefaultCtor; // no default construction - - FuncDeclarations dtors; // Array of destructors - FuncDeclaration dtor; // aggregate destructor - - Expression getRTInfo; // pointer to GC info generated by object.RTInfo(this) - - final extern (D) this(Loc loc, Identifier id) - { - super(id); - this.loc = loc; - protection = Prot(PROTpublic); - sizeok = SIZEOKnone; // size not determined yet - } - - /*************************************** - * Create a new scope from sc. - * semantic, semantic2 and semantic3 will use this for aggregate members. - */ - Scope* newScope(Scope* sc) - { - auto sc2 = sc.push(this); - sc2.stc &= STCsafe | STCtrusted | STCsystem; - sc2.parent = this; - if (isUnionDeclaration()) - sc2.inunion = 1; - sc2.protection = Prot(PROTpublic); - sc2.explicitProtection = 0; - sc2.aligndecl = null; - sc2.userAttribDecl = null; - return sc2; - } - - override final void setScope(Scope* sc) - { - // Might need a scope to resolve forward references. The check for - // semanticRun prevents unnecessary setting of _scope during deferred - // setScope phases for aggregates which already finished semantic(). - // See https://issues.dlang.org/show_bug.cgi?id=16607 - if (semanticRun < PASSsemanticdone) - ScopeDsymbol.setScope(sc); - } - - override final void semantic2(Scope* sc) - { - //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type.toChars(), errors); - if (!members) - return; - - if (_scope) - { - error("has forward references"); - return; - } - - auto sc2 = newScope(sc); - - determineSize(loc); - - for (size_t i = 0; i < members.dim; i++) - { - Dsymbol s = (*members)[i]; - //printf("\t[%d] %s\n", i, s.toChars()); - s.semantic2(sc2); - } - - sc2.pop(); - } - - override final void semantic3(Scope* sc) - { - //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors); - if (!members) - return; - - StructDeclaration sd = isStructDeclaration(); - if (!sc) // from runDeferredSemantic3 for TypeInfo generation - { - assert(sd); - sd.semanticTypeInfoMembers(); - return; - } - - auto sc2 = newScope(sc); - - for (size_t i = 0; i < members.dim; i++) - { - Dsymbol s = (*members)[i]; - s.semantic3(sc2); - } - - sc2.pop(); - - // don't do it for unused deprecated types - // or error types - if (!getRTInfo && Type.rtinfo && (!isDeprecated() || global.params.useDeprecated) && (type && type.ty != Terror)) - { - // Evaluate: RTinfo!type - auto tiargs = new Objects(); - tiargs.push(type); - auto ti = new TemplateInstance(loc, Type.rtinfo, tiargs); - - Scope* sc3 = ti.tempdecl._scope.startCTFE(); - sc3.tinst = sc.tinst; - sc3.minst = sc.minst; - if (isDeprecated()) - sc3.stc |= STCdeprecated; - - ti.semantic(sc3); - ti.semantic2(sc3); - ti.semantic3(sc3); - auto e = resolve(Loc(), sc3, ti.toAlias(), false); - - sc3.endCTFE(); - - e = e.ctfeInterpret(); - getRTInfo = e; - } - if (sd) - sd.semanticTypeInfoMembers(); - semanticRun = PASSsemantic3done; - } - - /*************************************** - * Find all instance fields, then push them into `fields`. - * - * Runs semantic() for all instance field variables, but also - * the field types can reamin yet not resolved forward references, - * except direct recursive definitions. - * After the process sizeok is set to SIZEOKfwd. - * - * Returns: - * false if any errors occur. - */ - final bool determineFields() - { - if (sizeok != SIZEOKnone) - return true; - - //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim); - // determineFields can be called recursively from one of the fields's v.semantic - fields.setDim(0); - - extern (C++) static int func(Dsymbol s, void* param) - { - auto v = s.isVarDeclaration(); - if (!v) - return 0; - if (v.storage_class & STCmanifest) - return 0; - - auto ad = cast(AggregateDeclaration)param; - - if (v.semanticRun < PASSsemanticdone) - v.semantic(null); - // Return in case a recursive determineFields triggered by v.semantic already finished - if (ad.sizeok != SIZEOKnone) - return 1; - - if (v.aliassym) - return 0; // If this variable was really a tuple, skip it. - - if (v.storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter)) - return 0; - if (!v.isField() || v.semanticRun < PASSsemanticdone) - return 1; // unresolvable forward reference - - ad.fields.push(v); - - if (v.storage_class & STCref) - return 0; - auto tv = v.type.baseElemOf(); - if (tv.ty != Tstruct) - return 0; - if (ad == (cast(TypeStruct)tv).sym) - { - const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : ""; - ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz); - ad.type = Type.terror; - ad.errors = true; - return 1; - } - return 0; - } - - for (size_t i = 0; i < members.dim; i++) - { - auto s = (*members)[i]; - if (s.apply(&func, cast(void*)this)) - { - if (sizeok != SIZEOKnone) - { - // recursive determineFields already finished - return true; - } - return false; - } - } - - if (sizeok != SIZEOKdone) - sizeok = SIZEOKfwd; - - return true; - } - - /*************************************** - * Collect all instance fields, then determine instance size. - * Returns: - * false if failed to determine the size. - */ - final bool determineSize(Loc loc) - { - //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok); - - // The previous instance size finalizing had: - if (type.ty == Terror) - return false; // failed already - if (sizeok == SIZEOKdone) - return true; // succeeded - - if (!members) - { - error(loc, "unknown size"); - return false; - } - - if (_scope) - semantic(null); - - // Determine the instance size of base class first. - if (auto cd = isClassDeclaration()) - { - cd = cd.baseClass; - if (cd && !cd.determineSize(loc)) - goto Lfail; - } - - // Determine instance fields when sizeok == SIZEOKnone - if (!determineFields()) - goto Lfail; - if (sizeok != SIZEOKdone) - finalizeSize(); - - // this aggregate type has: - if (type.ty == Terror) - return false; // marked as invalid during the finalizing. - if (sizeok == SIZEOKdone) - return true; // succeeded to calculate instance size. - - Lfail: - // There's unresolvable forward reference. - if (type != Type.terror) - error(loc, "no size because of forward reference"); - // Don't cache errors from speculative semantic, might be resolvable later. - // https://issues.dlang.org/show_bug.cgi?id=16574 - if (!global.gag) - { - type = Type.terror; - errors = true; - } - return false; - } - - abstract void finalizeSize(); - - override final d_uns64 size(Loc loc) - { - //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok); - bool ok = determineSize(loc); - //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok); - return ok ? structsize : SIZE_INVALID; - } - - /*************************************** - * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit - * field initializers have unique memory space on instance. - * Returns: - * true if any errors happen. - */ - final bool checkOverlappedFields() - { - //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars()); - assert(sizeok == SIZEOKdone); - size_t nfields = fields.dim; - if (isNested()) - { - auto cd = isClassDeclaration(); - if (!cd || !cd.baseClass || !cd.baseClass.isNested()) - nfields--; - } - bool errors = false; - - // Fill in missing any elements with default initializers - foreach (i; 0 .. nfields) - { - auto vd = fields[i]; - if (vd.errors) - { - errors = true; - continue; - } - - auto vx = vd; - if (vd._init && vd._init.isVoidInitializer()) - vx = null; - - // Find overlapped fields with the hole [vd.offset .. vd.offset.size()]. - foreach (j; 0 .. nfields) - { - if (i == j) - continue; - auto v2 = fields[j]; - if (v2.errors) - { - errors = true; - continue; - } - if (!vd.isOverlappedWith(v2)) - continue; - - // vd and v2 are overlapping. - vd.overlapped = true; - v2.overlapped = true; - - if (!MODimplicitConv(vd.type.mod, v2.type.mod)) - v2.overlapUnsafe = true; - if (!MODimplicitConv(v2.type.mod, vd.type.mod)) - vd.overlapUnsafe = true; - - if (!vx) - continue; - if (v2._init && v2._init.isVoidInitializer()) - continue; - - if (vx._init && v2._init) - { - .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); - errors = true; - } - } - } - return errors; - } - - /*************************************** - * Fill out remainder of elements[] with default initializers for fields[]. - * Params: - * loc = location - * elements = explicit arguments which given to construct object. - * ctorinit = true if the elements will be used for default initialization. - * Returns: - * false if any errors occur. - * Otherwise, returns true and the missing arguments will be pushed in elements[]. - */ - final bool fill(Loc loc, Expressions* elements, bool ctorinit) - { - //printf("AggregateDeclaration::fill() %s\n", toChars()); - assert(sizeok == SIZEOKdone); - assert(elements); - size_t nfields = fields.dim - isNested(); - bool errors = false; - - size_t dim = elements.dim; - elements.setDim(nfields); - foreach (size_t i; dim .. nfields) - (*elements)[i] = null; - - // Fill in missing any elements with default initializers - foreach (i; 0 .. nfields) - { - if ((*elements)[i]) - continue; - - auto vd = fields[i]; - auto vx = vd; - if (vd._init && vd._init.isVoidInitializer()) - vx = null; - - // Find overlapped fields with the hole [vd.offset .. vd.offset.size()]. - size_t fieldi = i; - foreach (j; 0 .. nfields) - { - if (i == j) - continue; - auto v2 = fields[j]; - if (!vd.isOverlappedWith(v2)) - continue; - - if ((*elements)[j]) - { - vx = null; - break; - } - if (v2._init && v2._init.isVoidInitializer()) - continue; - - version (all) - { - /* Prefer first found non-void-initialized field - * union U { int a; int b = 2; } - * U u; // Error: overlapping initialization for field a and b - */ - if (!vx) - { - vx = v2; - fieldi = j; - } - else if (v2._init) - { - .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); - errors = true; - } - } - else - { - // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always - - /* Prefer explicitly initialized field - * union U { int a; int b = 2; } - * U u; // OK (u.b == 2) - */ - if (!vx || !vx._init && v2._init) - { - vx = v2; - fieldi = j; - } - else if (vx != vd && !vx.isOverlappedWith(v2)) - { - // Both vx and v2 fills vd, but vx and v2 does not overlap - } - else if (vx._init && v2._init) - { - .error(loc, "overlapping default initialization for field `%s` and `%s`", - v2.toChars(), vd.toChars()); - errors = true; - } - else - assert(vx._init || !vx._init && !v2._init); - } - } - if (vx) - { - Expression e; - if (vx.type.size() == 0) - { - e = null; - } - else if (vx._init) - { - assert(!vx._init.isVoidInitializer()); - e = vx.getConstInitializer(false); - } - else - { - if ((vx.storage_class & STCnodefaultctor) && !ctorinit) - { - .error(loc, "field `%s.%s` must be initialized because it has no default constructor", - type.toChars(), vx.toChars()); - errors = true; - } - /* https://issues.dlang.org/show_bug.cgi?id=12509 - * Get the element of static array type. - */ - Type telem = vx.type; - if (telem.ty == Tsarray) - { - /* We cannot use Type::baseElemOf() here. - * If the bottom of the Tsarray is an enum type, baseElemOf() - * will return the base of the enum, and its default initializer - * would be different from the enum's. - */ - while (telem.toBasetype().ty == Tsarray) - telem = (cast(TypeSArray)telem.toBasetype()).next; - if (telem.ty == Tvoid) - telem = Type.tuns8.addMod(telem.mod); - } - if (telem.needsNested() && ctorinit) - e = telem.defaultInit(loc); - else - e = telem.defaultInitLiteral(loc); - } - (*elements)[fieldi] = e; - } - } - foreach (e; *elements) - { - if (e && e.op == TOKerror) - return false; - } - - return !errors; - } - - /**************************** - * Do byte or word alignment as necessary. - * Align sizes of 0, as we may not know array sizes yet. - * - * alignment: struct alignment that is in effect - * size: alignment requirement of field - */ - static void alignmember(structalign_t alignment, uint size, uint* poffset) - { - //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset); - switch (alignment) - { - case cast(structalign_t)1: - // No alignment - break; - - case cast(structalign_t)STRUCTALIGN_DEFAULT: - // Alignment in Target::fieldalignsize must match what the - // corresponding C compiler's default alignment behavior is. - assert(size > 0 && !(size & (size - 1))); - *poffset = (*poffset + size - 1) & ~(size - 1); - break; - - default: - // Align on alignment boundary, which must be a positive power of 2 - assert(alignment > 0 && !(alignment & (alignment - 1))); - *poffset = (*poffset + alignment - 1) & ~(alignment - 1); - break; - } - } - - /**************************************** - * Place a member (mem) into an aggregate (agg), which can be a struct, union or class - * Returns: - * offset to place field at - * - * nextoffset: next location in aggregate - * memsize: size of member - * memalignsize: natural alignment of member - * alignment: alignment in effect for this member - * paggsize: size of aggregate (updated) - * paggalignsize: alignment of aggregate (updated) - * isunion: the aggregate is a union - */ - static uint placeField(uint* nextoffset, uint memsize, uint memalignsize, - structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion) - { - uint ofs = *nextoffset; - - const uint actualAlignment = - alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment; - - // Ensure no overflow - bool overflow; - const sz = addu(memsize, actualAlignment, overflow); - const sum = addu(ofs, sz, overflow); - if (overflow) assert(0); - - alignmember(alignment, memalignsize, &ofs); - uint memoffset = ofs; - ofs += memsize; - if (ofs > *paggsize) - *paggsize = ofs; - if (!isunion) - *nextoffset = ofs; - - if (*paggalignsize < actualAlignment) - *paggalignsize = actualAlignment; - - return memoffset; - } - - override final Type getType() - { - return type; - } - - // is aggregate deprecated? - override final bool isDeprecated() - { - return isdeprecated; - } - - /**************************************** - * Returns true if there's an extra member which is the 'this' - * pointer to the enclosing context (enclosing aggregate or function) - */ - final bool isNested() - { - return enclosing !is null; - } - - /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested. - */ - final void makeNested() - { - if (enclosing) // if already nested - return; - if (sizeok == SIZEOKdone) - return; - if (isUnionDeclaration() || isInterfaceDeclaration()) - return; - if (storage_class & STCstatic) - return; - - // If nested struct, add in hidden 'this' pointer to outer scope - auto s = toParent2(); - if (!s) - return; - Type t = null; - if (auto fd = s.isFuncDeclaration()) - { - enclosing = fd; - - /* https://issues.dlang.org/show_bug.cgi?id=14422 - * If a nested class parent is a function, its - * context pointer (== `outer`) should be void* always. - */ - t = Type.tvoidptr; - } - else if (auto ad = s.isAggregateDeclaration()) - { - if (isClassDeclaration() && ad.isClassDeclaration()) - { - enclosing = ad; - } - else if (isStructDeclaration()) - { - if (auto ti = ad.parent.isTemplateInstance()) - { - enclosing = ti.enclosing; - } - } - t = ad.handleType(); - } - if (enclosing) - { - //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars()); - assert(t); - if (t.ty == Tstruct) - t = Type.tvoidptr; // t should not be a ref type - - assert(!vthis); - vthis = new ThisDeclaration(loc, t); - //vthis.storage_class |= STCref; - - // Emulate vthis.addMember() - members.push(vthis); - - // Emulate vthis.semantic() - vthis.storage_class |= STCfield; - vthis.parent = this; - vthis.protection = Prot(PROTpublic); - vthis.alignment = t.alignment(); - vthis.semanticRun = PASSsemanticdone; - - if (sizeok == SIZEOKfwd) - fields.push(vthis); - } - } - - override final bool isExport() - { - return protection.kind == PROTexport; - } - - /******************************************* - * Look for constructor declaration. - */ - final Dsymbol searchCtor() - { - auto s = search(Loc(), Id.ctor); - if (s) - { - if (!(s.isCtorDeclaration() || - s.isTemplateDeclaration() || - s.isOverloadSet())) - { - s.error("is not a constructor; identifiers starting with __ are reserved for the implementation"); - errors = true; - s = null; - } - } - if (s && s.toParent() != this) - s = null; // search() looks through ancestor classes - if (s) - { - // Finish all constructors semantics to determine this.noDefaultCtor. - struct SearchCtor - { - extern (C++) static int fp(Dsymbol s, void* ctxt) - { - auto f = s.isCtorDeclaration(); - if (f && f.semanticRun == PASSinit) - f.semantic(null); - return 0; - } - } - - for (size_t i = 0; i < members.dim; i++) - { - auto sm = (*members)[i]; - sm.apply(&SearchCtor.fp, null); - } - } - return s; - } - - override final Prot prot() - { - return protection; - } - - // 'this' type - final Type handleType() - { - return type; - } - - // Back end - Symbol* stag; // tag symbol for debug data - Symbol* sinit; - - override final inout(AggregateDeclaration) isAggregateDeclaration() inout - { - return this; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} diff -Nru ldc-1.6.0/ddmd/aggregate.h ldc-1.8.0/ddmd/aggregate.h --- ldc-1.6.0/ddmd/aggregate.h 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/aggregate.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,337 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (c) 1999-2016 by Digital Mars - * All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/dlang/dmd/blob/master/src/aggregate.h - */ - -#ifndef DMD_AGGREGATE_H -#define DMD_AGGREGATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" - -#include "dsymbol.h" -#include "declaration.h" -#include "objc.h" - -class Identifier; -class Type; -class TypeFunction; -class Expression; -class FuncDeclaration; -class CtorDeclaration; -class DtorDeclaration; -class InvariantDeclaration; -class NewDeclaration; -class DeleteDeclaration; -class InterfaceDeclaration; -class TypeInfoClassDeclaration; -class VarDeclaration; - -enum Sizeok -{ - SIZEOKnone, // size of aggregate is not yet able to compute - SIZEOKfwd, // size of aggregate is ready to compute - SIZEOKdone, // size of aggregate is set correctly -}; - -enum Baseok -{ - BASEOKnone, // base classes not computed yet - BASEOKin, // in process of resolving base classes - BASEOKdone, // all base classes are resolved - BASEOKsemanticdone, // all base classes semantic done -}; - -enum StructPOD -{ - ISPODno, // struct is not POD - ISPODyes, // struct is POD - ISPODfwd, // POD not yet computed -}; - -enum Abstract -{ - ABSfwdref = 0, // whether an abstract class is not yet computed - ABSyes, // is abstract class - ABSno, // is not abstract class -}; - -FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc); -FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc); -bool needOpEquals(StructDeclaration *sd); -FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc); -FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc); -FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc); -FuncDeclaration *buildXtoHash(StructDeclaration *ad, Scope *sc); -FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc); -FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc); -FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc); - -class AggregateDeclaration : public ScopeDsymbol -{ -public: - Type *type; - StorageClass storage_class; - Prot protection; - unsigned structsize; // size of struct - unsigned alignsize; // size of struct for alignment purposes - VarDeclarations fields; // VarDeclaration fields - Sizeok sizeok; // set when structsize contains valid data - Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol - bool isdeprecated; // true if deprecated - - /* !=NULL if is nested - * pointing to the dsymbol that directly enclosing it. - * 1. The function that enclosing it (nested struct and class) - * 2. The class that enclosing it (nested class only) - * 3. If enclosing aggregate is template, its enclosing dsymbol. - * See AggregateDeclaraton::makeNested for the details. - */ - Dsymbol *enclosing; - VarDeclaration *vthis; // 'this' parameter if this aggregate is nested - // Special member functions - FuncDeclarations invs; // Array of invariants - FuncDeclaration *inv; // invariant - NewDeclaration *aggNew; // allocator - DeleteDeclaration *aggDelete; // deallocator - - Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration - - // default constructor - should have no arguments, because - // it would be stored in TypeInfo_Class.defaultConstructor - CtorDeclaration *defaultCtor; - - Dsymbol *aliasthis; // forward unresolved lookups to aliasthis - bool noDefaultCtor; // no default construction - - FuncDeclarations dtors; // Array of destructors - FuncDeclaration *dtor; // aggregate destructor - - Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this) - - virtual Scope *newScope(Scope *sc); - void setScope(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - bool determineFields(); - bool determineSize(Loc loc); - virtual void finalizeSize() = 0; - d_uns64 size(Loc loc); - bool checkOverlappedFields(); - bool fill(Loc loc, Expressions *elements, bool ctorinit); - static void alignmember(structalign_t salign, unsigned size, unsigned *poffset); - static unsigned placeField(unsigned *nextoffset, - unsigned memsize, unsigned memalignsize, structalign_t memalign, - unsigned *paggsize, unsigned *paggalignsize, bool isunion); - Type *getType(); - bool isDeprecated(); // is aggregate deprecated? - bool isNested(); - void makeNested(); - bool isExport(); - Dsymbol *searchCtor(); - - Prot prot(); - - // 'this' type - Type *handleType() { return type; } - - // Back end - Symbol *stag; // tag symbol for debug data - Symbol *sinit; - - AggregateDeclaration *isAggregateDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } -}; - -struct StructFlags -{ - typedef unsigned Type; - enum Enum - { - hasPointers = 0x1, // NB: should use noPointers as in ClassFlags - }; -}; - -class StructDeclaration : public AggregateDeclaration -{ -public: - int zeroInit; // !=0 if initialize with 0 fill - bool hasIdentityAssign; // true if has identity opAssign - bool hasIdentityEquals; // true if has identity opEquals - FuncDeclarations postblits; // Array of postblit functions - FuncDeclaration *postblit; // aggregate postblit - - FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals - FuncDeclaration *xcmp; // TypeInfo_Struct.xopCmp - FuncDeclaration *xhash; // TypeInfo_Struct.xtoHash - static FuncDeclaration *xerreq; // object.xopEquals - static FuncDeclaration *xerrcmp; // object.xopCmp - - structalign_t alignment; // alignment applied outside of the struct - StructPOD ispod; // if struct is POD - - // For 64 bit Efl function call/return ABI - Type *arg1type; - Type *arg2type; - - // Even if struct is defined as non-root symbol, some built-in operations - // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo. - // For those, today TypeInfo_Struct is generated in COMDAT. - bool requestTypeInfo; - - static StructDeclaration *create(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void semanticTypeInfoMembers(); - Dsymbol *search(Loc, Identifier *ident, int flags = SearchLocalsOnly); - const char *kind(); - void finalizeSize(); - bool fit(Loc loc, Scope *sc, Expressions *elements, Type *stype); - bool isPOD(); - - StructDeclaration *isStructDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } -}; - -class UnionDeclaration : public StructDeclaration -{ -public: - Dsymbol *syntaxCopy(Dsymbol *s); - const char *kind(); - - UnionDeclaration *isUnionDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } -}; - -struct BaseClass -{ - Type *type; // (before semantic processing) - - ClassDeclaration *sym; - unsigned offset; // 'this' pointer offset - // for interfaces: Array of FuncDeclaration's - // making up the vtbl[] - FuncDeclarations vtbl; - - DArray baseInterfaces; // if BaseClass is an interface, these - // are a copy of the InterfaceDeclaration::interfaces - - BaseClass(); - BaseClass(Type *type); - - bool fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance); - void copyBaseInterfaces(BaseClasses *); -}; - -struct ClassFlags -{ - typedef unsigned Type; - enum Enum - { - isCOMclass = 0x1, - noPointers = 0x2, - hasOffTi = 0x4, - hasCtor = 0x8, - hasGetMembers = 0x10, - hasTypeInfo = 0x20, - isAbstract = 0x40, - isCPPclass = 0x80, - hasDtor = 0x100, - }; -}; - -class ClassDeclaration : public AggregateDeclaration -{ -public: - static ClassDeclaration *object; - static ClassDeclaration *throwable; - static ClassDeclaration *exception; - static ClassDeclaration *errorException; - static ClassDeclaration *cpp_type_info_ptr; - - ClassDeclaration *baseClass; // NULL only if this is Object - FuncDeclaration *staticCtor; - FuncDeclaration *staticDtor; - Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[] - Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[] - - BaseClasses *baseclasses; // Array of BaseClass's; first is super, - // rest are Interface's - - DArray interfaces; // interfaces[interfaces_dim] for this class - // (does not include baseClass) - - BaseClasses *vtblInterfaces; // array of base interfaces that have - // their own vtbl[] - - TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration - bool com; // true if this is a COM class (meaning it derives from IUnknown) - bool cpp; // true if this is a C++ interface - bool isobjc; // true if this is an Objective-C class/interface - bool isscope; // true if this is a scope class - Abstract isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract - int inuse; // to prevent recursive attempts - Baseok baseok; // set the progress of base classes resolving - Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr - - static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject); - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void semantic(Scope *sc); - bool isBaseOf2(ClassDeclaration *cd); - - #define OFFSET_RUNTIME 0x76543210 - #define OFFSET_FWDREF 0x76543211 - virtual bool isBaseOf(ClassDeclaration *cd, int *poffset); - - bool isBaseInfoComplete(); - Dsymbol *search(Loc, Identifier *ident, int flags = SearchLocalsOnly); - ClassDeclaration *searchBase(Identifier *ident); - void finalizeSize(); - bool isFuncHidden(FuncDeclaration *fd); - FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); - void interfaceSemantic(Scope *sc); - bool isCOMclass() const; - virtual bool isCOMinterface() const; - bool isCPPclass() const; - virtual bool isCPPinterface() const; - bool isAbstract(); - virtual int vtblOffset() const; - const char *kind(); - - void addLocalClass(ClassDeclarations *); - - // Back end - Symbol *vtblsym; - - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } - void accept(Visitor *v) { v->visit(this); } -}; - -class InterfaceDeclaration : public ClassDeclaration -{ -public: - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void semantic(Scope *sc); - bool isBaseOf(ClassDeclaration *cd, int *poffset); - bool isBaseOf(BaseClass *bc, int *poffset); - const char *kind(); - int vtblOffset() const; - bool isCPPinterface() const; - bool isCOMinterface() const; - - InterfaceDeclaration *isInterfaceDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } -}; - -#endif /* DMD_AGGREGATE_H */ diff -Nru ldc-1.6.0/ddmd/aliasthis.d ldc-1.8.0/ddmd/aliasthis.d --- ldc-1.6.0/ddmd/aliasthis.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/aliasthis.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,178 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/aliasthis.d, _aliasthis.d) - */ - -module ddmd.aliasthis; - -// Online documentation: https://dlang.org/phobos/ddmd_aliasthis.html - -import core.stdc.stdio; -import ddmd.aggregate; -import ddmd.declaration; -import ddmd.dscope; -import ddmd.dsymbol; -import ddmd.errors; -import ddmd.expression; -import ddmd.expressionsem; -import ddmd.globals; -import ddmd.identifier; -import ddmd.mtype; -import ddmd.opover; -import ddmd.tokens; -import ddmd.visitor; - -/*********************************************************** - * alias ident this; - */ -extern (C++) final class AliasThis : Dsymbol -{ - Identifier ident; - - extern (D) this(Loc loc, Identifier ident) - { - super(null); // it's anonymous (no identifier) - this.loc = loc; - this.ident = ident; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new AliasThis(loc, ident); - } - - override void semantic(Scope* sc) - { - if (semanticRun != PASSinit) - return; - - if (_scope) - { - sc = _scope; - _scope = null; - } - - if (!sc) - return; - - semanticRun = PASSsemantic; - - Dsymbol p = sc.parent.pastMixin(); - AggregateDeclaration ad = p.isAggregateDeclaration(); - if (!ad) - { - .error(loc, "alias this can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); - return; - } - - assert(ad.members); - Dsymbol s = ad.search(loc, ident); - if (!s) - { - s = sc.search(loc, ident, null); - if (s) - .error(loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars()); - else - .error(loc, "undefined identifier `%s`", ident.toChars()); - return; - } - if (ad.aliasthis && s != ad.aliasthis) - { - .error(loc, "there can be only one alias this"); - return; - } - - /* disable the alias this conversion so the implicit conversion check - * doesn't use it. - */ - ad.aliasthis = null; - - Dsymbol sx = s; - if (sx.isAliasDeclaration()) - sx = sx.toAlias(); - Declaration d = sx.isDeclaration(); - if (d && !d.isTupleDeclaration()) - { - Type t = d.type; - assert(t); - if (ad.type.implicitConvTo(t) > MATCHnomatch) - { - .error(loc, "alias this is not reachable as `%s` already converts to `%s`", ad.toChars(), t.toChars()); - } - } - - ad.aliasthis = s; - semanticRun = PASSsemanticdone; - } - - override const(char)* kind() const - { - return "alias this"; - } - - AliasThis isAliasThis() - { - return this; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -extern (C++) Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false) -{ - AggregateDeclaration ad = isAggregate(e.type); - if (ad && ad.aliasthis) - { - uint olderrors = gag ? global.startGagging() : 0; - Loc loc = e.loc; - Type tthis = (e.op == TOKtype ? e.type : null); - e = new DotIdExp(loc, e, ad.aliasthis.ident); - e = e.semantic(sc); - if (tthis && ad.aliasthis.needThis()) - { - if (e.op == TOKvar) - { - if (auto fd = (cast(VarExp)e).var.isFuncDeclaration()) - { - // https://issues.dlang.org/show_bug.cgi?id=13009 - // Support better match for the overloaded alias this. - bool hasOverloads; - if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) - { - if (!hasOverloads) - fd = f; // use exact match - e = new VarExp(loc, fd, hasOverloads); - e.type = f.type; - e = new CallExp(loc, e); - goto L1; - } - } - } - /* non-@property function is not called inside typeof(), - * so resolve it ahead. - */ - { - int save = sc.intypeof; - sc.intypeof = 1; // bypass "need this" error check - e = resolveProperties(sc, e); - sc.intypeof = save; - } - L1: - e = new TypeExp(loc, new TypeTypeof(loc, e)); - e = e.semantic(sc); - } - e = resolveProperties(sc, e); - if (gag && global.endGagging(olderrors)) - e = null; - } - return e; -} diff -Nru ldc-1.6.0/ddmd/aliasthis.h ldc-1.8.0/ddmd/aliasthis.h --- ldc-1.6.0/ddmd/aliasthis.h 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/aliasthis.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (c) 2009-2014 by Digital Mars - * All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/dlang/dmd/blob/master/src/aliasthis.h - */ - -#ifndef DMD_ALIASTHIS_H -#define DMD_ALIASTHIS_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "mars.h" -#include "dsymbol.h" - -/**************************************************************/ - -class AliasThis : public Dsymbol -{ -public: - // alias Identifier this; - Identifier *ident; - - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - const char *kind(); - AliasThis *isAliasThis() { return this; } - void accept(Visitor *v) { v->visit(this); } -}; - -#endif diff -Nru ldc-1.6.0/ddmd/apply.d ldc-1.8.0/ddmd/apply.d --- ldc-1.6.0/ddmd/apply.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/apply.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/apply.d, _apply.d) - */ - -module ddmd.apply; - -// Online documentation: https://dlang.org/phobos/ddmd_apply.html - -import ddmd.arraytypes; -import ddmd.dtemplate; -import ddmd.expression; -import ddmd.visitor; - -/************************************** - * An Expression tree walker that will visit each Expression e in the tree, - * in depth-first evaluation order, and call fp(e,param) on it. - * fp() signals whether the walking continues with its return value: - * Returns: - * 0 continue - * 1 done - * It's a bit slower than using virtual functions, but more encapsulated and less brittle. - * Creating an iterator for this would be much more complex. - */ -extern (C++) final class PostorderExpressionVisitor : StoppableVisitor -{ - alias visit = super.visit; -public: - StoppableVisitor v; - - extern (D) this(StoppableVisitor v) - { - this.v = v; - } - - bool doCond(Expression e) - { - if (!stop && e) - e.accept(this); - return stop; - } - - bool doCond(Expressions* e) - { - if (!e) - return false; - for (size_t i = 0; i < e.dim && !stop; i++) - doCond((*e)[i]); - return stop; - } - - bool applyTo(Expression e) - { - e.accept(v); - stop = v.stop; - return true; - } - - override void visit(Expression e) - { - applyTo(e); - } - - override void visit(NewExp e) - { - //printf("NewExp::apply(): %s\n", toChars()); - doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e); - } - - override void visit(NewAnonClassExp e) - { - //printf("NewAnonClassExp::apply(): %s\n", toChars()); - doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e); - } - - override void visit(TypeidExp e) - { - doCond(isExpression(e.obj)) || applyTo(e); - } - - override void visit(UnaExp e) - { - doCond(e.e1) || applyTo(e); - } - - override void visit(BinExp e) - { - doCond(e.e1) || doCond(e.e2) || applyTo(e); - } - - override void visit(AssertExp e) - { - //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); - doCond(e.e1) || doCond(e.msg) || applyTo(e); - } - - override void visit(CallExp e) - { - //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); - doCond(e.e1) || doCond(e.arguments) || applyTo(e); - } - - override void visit(ArrayExp e) - { - //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); - doCond(e.e1) || doCond(e.arguments) || applyTo(e); - } - - override void visit(SliceExp e) - { - doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e); - } - - override void visit(ArrayLiteralExp e) - { - doCond(e.basis) || doCond(e.elements) || applyTo(e); - } - - override void visit(AssocArrayLiteralExp e) - { - doCond(e.keys) || doCond(e.values) || applyTo(e); - } - - override void visit(StructLiteralExp e) - { - if (e.stageflags & stageApply) - return; - int old = e.stageflags; - e.stageflags |= stageApply; - doCond(e.elements) || applyTo(e); - e.stageflags = old; - } - - override void visit(TupleExp e) - { - doCond(e.e0) || doCond(e.exps) || applyTo(e); - } - - override void visit(CondExp e) - { - doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e); - } -} - -extern (C++) bool walkPostorder(Expression e, StoppableVisitor v) -{ - scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v); - e.accept(pv); - return v.stop; -} diff -Nru ldc-1.6.0/ddmd/argtypes.d ldc-1.8.0/ddmd/argtypes.d --- ldc-1.6.0/ddmd/argtypes.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/argtypes.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,464 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/argtypes.d, _argtypes.d) - */ - -module ddmd.argtypes; - -// Online documentation: https://dlang.org/phobos/ddmd_argtypes.html - -import core.stdc.stdio; -import ddmd.declaration; -import ddmd.globals; -import ddmd.mtype; -import ddmd.visitor; - -/**************************************************** - * This breaks a type down into 'simpler' types that can be passed to a function - * in registers, and returned in registers. - * It's highly platform dependent. - * Params: - * t = type to break down - * Returns: - * tuple of types, each element can be passed in a register. - * A tuple of zero length means the type cannot be passed/returned in registers. - */ -extern (C++) TypeTuple toArgTypes(Type t) -{ - extern (C++) final class ToArgTypes : Visitor - { - alias visit = super.visit; - public: - TypeTuple result; - - override void visit(Type) - { - // not valid for a parameter - } - - override void visit(TypeError) - { - result = new TypeTuple(Type.terror); - } - - override void visit(TypeBasic t) - { - Type t1 = null; - Type t2 = null; - switch (t.ty) - { - case Tvoid: - return; - case Tbool: - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tint32: - case Tuns32: - case Tfloat32: - case Tint64: - case Tuns64: - case Tint128: - case Tuns128: - case Tfloat64: - case Tfloat80: - t1 = t; - break; - case Timaginary32: - t1 = Type.tfloat32; - break; - case Timaginary64: - t1 = Type.tfloat64; - break; - case Timaginary80: - t1 = Type.tfloat80; - break; - case Tcomplex32: - if (global.params.is64bit) - t1 = Type.tfloat64; - else - { - t1 = Type.tfloat64; - t2 = Type.tfloat64; - } - break; - case Tcomplex64: - t1 = Type.tfloat64; - t2 = Type.tfloat64; - break; - case Tcomplex80: - t1 = Type.tfloat80; - t2 = Type.tfloat80; - break; - case Tchar: - t1 = Type.tuns8; - break; - case Twchar: - t1 = Type.tuns16; - break; - case Tdchar: - t1 = Type.tuns32; - break; - default: - assert(0); - } - if (t1) - { - if (t2) - result = new TypeTuple(t1, t2); - else - result = new TypeTuple(t1); - } - else - result = new TypeTuple(); - } - - override void visit(TypeVector t) - { - result = new TypeTuple(t); - } - - override void visit(TypeSArray t) - { - if (t.dim) - { - /* Should really be done as if it were a struct with dim members - * of the array's elements. - * I.e. int[2] should be done like struct S { int a; int b; } - */ - dinteger_t sz = t.dim.toInteger(); - // T[1] should be passed like T - if (sz == 1) - { - t.next.accept(this); - return; - } - } - result = new TypeTuple(); // pass on the stack for efficiency - } - - override void visit(TypeAArray) - { - result = new TypeTuple(Type.tvoidptr); - } - - override void visit(TypePointer) - { - result = new TypeTuple(Type.tvoidptr); - } - - /************************************* - * Convert a floating point type into the equivalent integral type. - */ - static Type mergeFloatToInt(Type t) - { - switch (t.ty) - { - case Tfloat32: - case Timaginary32: - t = Type.tint32; - break; - case Tfloat64: - case Timaginary64: - case Tcomplex32: - t = Type.tint64; - break; - default: - debug - { - printf("mergeFloatToInt() %s\n", t.toChars()); - } - assert(0); - } - return t; - } - - /************************************* - * This merges two types into an 8byte type. - * Params: - * t1 = first type (can be null) - * t2 = second type (can be null) - * offset2 = offset of t2 from start of t1 - * Returns: - * type that encompasses both t1 and t2, null if cannot be done - */ - static Type argtypemerge(Type t1, Type t2, uint offset2) - { - //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1.toChars() : "", t2 ? t2.toChars() : "", offset2); - if (!t1) - { - assert(!t2 || offset2 == 0); - return t2; - } - if (!t2) - return t1; - const sz1 = t1.size(Loc()); - const sz2 = t2.size(Loc()); - assert(sz1 != SIZE_INVALID && sz2 != SIZE_INVALID); - if (t1.ty != t2.ty && (t1.ty == Tfloat80 || t2.ty == Tfloat80)) - return null; - // [float,float] => [cfloat] - if (t1.ty == Tfloat32 && t2.ty == Tfloat32 && offset2 == 4) - return Type.tfloat64; - // Merging floating and non-floating types produces the non-floating type - if (t1.isfloating()) - { - if (!t2.isfloating()) - t1 = mergeFloatToInt(t1); - } - else if (t2.isfloating()) - t2 = mergeFloatToInt(t2); - Type t; - // Pick type with larger size - if (sz1 < sz2) - t = t2; - else - t = t1; - // If t2 does not lie within t1, need to increase the size of t to enclose both - assert(sz2 < sz2.max - offset2.max); - if (offset2 && sz1 < offset2 + sz2) - { - switch (offset2 + sz2) - { - case 2: - t = Type.tint16; - break; - case 3: - case 4: - t = Type.tint32; - break; - default: - t = Type.tint64; - break; - } - } - return t; - } - - override void visit(TypeDArray) - { - /* Should be done as if it were: - * struct S { size_t length; void* ptr; } - */ - if (global.params.is64bit && !global.params.isLP64) - { - // For AMD64 ILP32 ABI, D arrays fit into a single integer register. - uint offset = cast(uint)Type.tsize_t.size(Loc()); - Type t = argtypemerge(Type.tsize_t, Type.tvoidptr, offset); - if (t) - { - result = new TypeTuple(t); - return; - } - } - result = new TypeTuple(Type.tsize_t, Type.tvoidptr); - } - - override void visit(TypeDelegate) - { - /* Should be done as if it were: - * struct S { size_t length; void* ptr; } - */ - if (global.params.is64bit && !global.params.isLP64) - { - // For AMD64 ILP32 ABI, delegates fit into a single integer register. - uint offset = cast(uint)Type.tsize_t.size(Loc()); - Type t = argtypemerge(Type.tsize_t, Type.tvoidptr, offset); - if (t) - { - result = new TypeTuple(t); - return; - } - } - result = new TypeTuple(Type.tvoidptr, Type.tvoidptr); - } - - override void visit(TypeStruct t) - { - //printf("TypeStruct.toArgTypes() %s\n", t.toChars()); - if (!t.sym.isPOD() || t.sym.fields.dim == 0) - { - Lmemory: - //printf("\ttoArgTypes() %s => [ ]\n", t.toChars()); - result = new TypeTuple(); // pass on the stack - return; - } - Type t1 = null; - Type t2 = null; - const sz = t.size(Loc()); - assert(sz < 0xFFFFFFFF); - switch (cast(uint)sz) - { - case 1: - t1 = Type.tint8; - break; - case 2: - t1 = Type.tint16; - break; - case 3: - if (!global.params.is64bit) - goto Lmemory; - goto case; - case 4: - t1 = Type.tint32; - break; - case 5: - case 6: - case 7: - if (!global.params.is64bit) - goto Lmemory; - goto case; - case 8: - t1 = Type.tint64; - break; - case 16: - t1 = null; // could be a TypeVector - break; - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - if (!global.params.is64bit) - goto Lmemory; - t1 = null; - break; - default: - goto Lmemory; - } - if (global.params.is64bit && t.sym.fields.dim) - { - version (all) - { - t1 = null; - for (size_t i = 0; i < t.sym.fields.dim; i++) - { - VarDeclaration f = t.sym.fields[i]; - //printf(" [%d] %s f.type = %s\n", cast(int)i, f.toChars(), f.type.toChars()); - TypeTuple tup = toArgTypes(f.type); - if (!tup) - goto Lmemory; - size_t dim = tup.arguments.dim; - Type ft1 = null; - Type ft2 = null; - switch (dim) - { - case 2: - ft1 = (*tup.arguments)[0].type; - ft2 = (*tup.arguments)[1].type; - break; - case 1: - if (f.offset < 8) - ft1 = (*tup.arguments)[0].type; - else - ft2 = (*tup.arguments)[0].type; - break; - default: - goto Lmemory; - } - if (f.offset & 7) - { - // Misaligned fields goto Lmemory - uint alignsz = f.type.alignsize(); - if (f.offset & (alignsz - 1)) - goto Lmemory; - // Fields that overlap the 8byte boundary goto Lmemory - const fieldsz = f.type.size(Loc()); - assert(fieldsz != SIZE_INVALID && fieldsz < fieldsz.max - f.offset.max); - if (f.offset < 8 && (f.offset + fieldsz) > 8) - goto Lmemory; - } - // First field in 8byte must be at start of 8byte - assert(t1 || f.offset == 0); - //printf("ft1 = %s\n", ft1 ? ft1.toChars() : "null"); - //printf("ft2 = %s\n", ft2 ? ft2.toChars() : "null"); - if (ft1) - { - t1 = argtypemerge(t1, ft1, f.offset); - if (!t1) - goto Lmemory; - } - if (ft2) - { - uint off2 = f.offset; - if (ft1) - off2 = 8; - if (!t2 && off2 != 8) - goto Lmemory; - assert(t2 || off2 == 8); - t2 = argtypemerge(t2, ft2, off2 - 8); - if (!t2) - goto Lmemory; - } - } - if (t2) - { - if (t1.isfloating() && t2.isfloating()) - { - if ((t1.ty == Tfloat32 || t1.ty == Tfloat64) && (t2.ty == Tfloat32 || t2.ty == Tfloat64)) - { - } - else - goto Lmemory; - } - else if (t1.isfloating()) - goto Lmemory; - else if (t2.isfloating()) - goto Lmemory; - else - { - } - } - } - else - { - if (t.sym.fields.dim == 1) - { - VarDeclaration f = t.sym.fields[0]; - //printf("f.type = %s\n", f.type.toChars()); - TypeTuple tup = toArgTypes(f.type); - if (tup) - { - size_t dim = tup.arguments.dim; - if (dim == 1) - t1 = (*tup.arguments)[0].type; - } - } - } - } - //printf("\ttoArgTypes() %s => [%s,%s]\n", t.toChars(), t1 ? t1.toChars() : "", t2 ? t2.toChars() : ""); - if (t1) - { - //if (t1) printf("test1: %s => %s\n", toChars(), t1.toChars()); - if (t2) - result = new TypeTuple(t1, t2); - else - result = new TypeTuple(t1); - } - else - goto Lmemory; - } - - override void visit(TypeEnum t) - { - t.toBasetype().accept(this); - } - - override void visit(TypeClass) - { - result = new TypeTuple(Type.tvoidptr); - } - } - - scope ToArgTypes v = new ToArgTypes(); - t.accept(v); - return v.result; -} diff -Nru ldc-1.6.0/ddmd/arrayop.d ldc-1.8.0/ddmd/arrayop.d --- ldc-1.6.0/ddmd/arrayop.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/arrayop.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,663 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/arrayop.d, _arrayop.d) - */ - -module ddmd.arrayop; - -// Online documentation: https://dlang.org/phobos/ddmd_arrayop.html - -import core.stdc.stdio; -import ddmd.arraytypes; -import ddmd.declaration; -import ddmd.dscope; -import ddmd.dsymbol; -import ddmd.expression; -import ddmd.expressionsem; -import ddmd.func; -import ddmd.globals; -import ddmd.id; -import ddmd.identifier; -import ddmd.mtype; -import ddmd.root.outbuffer; -import ddmd.statement; -import ddmd.tokens; -import ddmd.visitor; - -/************************************** - * Hash table of array op functions already generated or known about. - */ -version(IN_LLVM) {} else -private __gshared FuncDeclaration[void*] arrayfuncs; - - -/************************************** - * Structure to contain information needed to insert an array op call - */ -extern (C++) FuncDeclaration buildArrayOp(Identifier ident, BinExp exp, Scope* sc, Loc loc) -{ - auto fparams = new Parameters(); - Expression loopbody = buildArrayLoop(exp, fparams); - - /* Construct the function body: - * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) - * loopbody; - * return p; - */ - - Parameter p = (*fparams)[0]; - // foreach (i; 0 .. p.length) - Statement s1 = new ForeachRangeStatement(Loc(), TOKforeach, - new Parameter(0, null, Id.p, null), - new IntegerExp(Loc(), 0, Type.tsize_t), - new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p.ident)), - new ExpStatement(Loc(), loopbody), - Loc()); - //printf("%s\n", s1.toChars()); - Statement s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p.ident)); - //printf("s2: %s\n", s2.toChars()); - Statement fbody = new CompoundStatement(Loc(), s1, s2); - - // Built-in array ops should be @trusted, pure, nothrow and nogc - StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc; - - /* Construct the function - */ - auto ftype = new TypeFunction(fparams, exp.e1.type, 0, LINKc, stc); - //printf("fd: %s %s\n", ident.toChars(), ftype.toChars()); - //printf("fbody: %s\n", fbody.toChars()); - auto fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype); - fd.fbody = fbody; - fd.protection = Prot(PROTpublic); - fd.linkage = LINKc; - fd.isArrayOp = 1; - - sc._module.importedFrom.members.push(fd); - - sc = sc.push(); - sc.parent = sc._module.importedFrom; - sc.stc = 0; - sc.linkage = LINKc; - fd.semantic(sc); - fd.semantic2(sc); - uint errors = global.startGagging(); - fd.semantic3(sc); - if (global.endGagging(errors)) - { - fd.type = Type.terror; - fd.errors = true; - fd.fbody = null; - } - sc.pop(); - - return fd; -} - -/********************************************** - * Check that there are no uses of arrays without []. - */ -extern (C++) bool isArrayOpValid(Expression e) -{ - if (e.op == TOKslice) - return true; - if (e.op == TOKarrayliteral) - { - Type t = e.type.toBasetype(); - while (t.ty == Tarray || t.ty == Tsarray) - t = t.nextOf().toBasetype(); - return (t.ty != Tvoid); - } - Type tb = e.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - if (isUnaArrayOp(e.op)) - { - return isArrayOpValid((cast(UnaExp)e).e1); - } - if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == TOKassign) - { - BinExp be = cast(BinExp)e; - return isArrayOpValid(be.e1) && isArrayOpValid(be.e2); - } - if (e.op == TOKconstruct) - { - BinExp be = cast(BinExp)e; - return be.e1.op == TOKslice && isArrayOpValid(be.e2); - } - if (e.op == TOKcall) - { - return false; // TODO: Decide if [] is required after arrayop calls. - } - else - { - return false; - } - } - return true; -} - -extern (C++) bool isNonAssignmentArrayOp(Expression e) -{ - if (e.op == TOKslice) - return isNonAssignmentArrayOp((cast(SliceExp)e).e1); - - Type tb = e.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - return (isUnaArrayOp(e.op) || isBinArrayOp(e.op)); - } - return false; -} - -extern (C++) bool checkNonAssignmentArrayOp(Expression e, bool suggestion = false) -{ - if (isNonAssignmentArrayOp(e)) - { - const(char)* s = ""; - if (suggestion) - s = " (possible missing [])"; - e.error("array operation `%s` without destination memory not allowed%s", e.toChars(), s); - return true; - } - return false; -} - -/*********************************** - * Construct the array operation expression. - */ -extern (C++) Expression arrayOp(BinExp e, Scope* sc) -{ - //printf("BinExp.arrayOp() %s\n", toChars()); - Type tb = e.type.toBasetype(); - assert(tb.ty == Tarray || tb.ty == Tsarray); - Type tbn = tb.nextOf().toBasetype(); - if (tbn.ty == Tvoid) - { - e.error("cannot perform array operations on `void[]` arrays"); - return new ErrorExp(); - } - if (!isArrayOpValid(e)) - return arrayOpInvalidError(e); - - auto arguments = new Expressions(); - - /* The expression to generate an array operation for is mangled - * into a name to use as the array operation function name. - * Mangle in the operands and operators in RPN order, and type. - */ - OutBuffer buf; - buf.writestring("_array"); - buildArrayIdent(e, &buf, arguments); - buf.writeByte('_'); - - /* Append deco of array element type - */ - buf.writestring(e.type.toBasetype().nextOf().toBasetype().mutableOf().deco); - - auto ident = Identifier.idPool(buf.peekSlice()); - - version(IN_LLVM) - { - FuncDeclaration* pFd = cast(void*)ident in sc._module.arrayfuncs; - } - else - { - FuncDeclaration* pFd = cast(void*)ident in arrayfuncs; - } - FuncDeclaration fd; - if (pFd) - fd = *pFd; - else - fd = buildArrayOp(ident, e, sc, e.loc); - - if (fd && fd.errors) - { - const(char)* fmt; - if (tbn.ty == Tstruct || tbn.ty == Tclass) - fmt = "invalid array operation `%s` because `%s` doesn't support necessary arithmetic operations"; - else if (!tbn.isscalar()) - fmt = "invalid array operation `%s` because `%s` is not a scalar type"; - else - fmt = "invalid array operation `%s` for element type `%s`"; - e.error(fmt, e.toChars(), tbn.toChars()); - return new ErrorExp(); - } - - if (!pFd) - { - version(IN_LLVM) - { - sc._module.arrayfuncs[cast(void*)ident] = fd; - } - else - { - arrayfuncs[cast(void*)ident] = fd; - } - } - - Expression ev = new VarExp(e.loc, fd); - Expression ec = new CallExp(e.loc, ev, arguments); - return ec.semantic(sc); -} - -extern (C++) Expression arrayOp(BinAssignExp e, Scope* sc) -{ - //printf("BinAssignExp.arrayOp() %s\n", toChars()); - - /* Check that the elements of e1 can be assigned to - */ - Type tn = e.e1.type.toBasetype().nextOf(); - - if (tn && (!tn.isMutable() || !tn.isAssignable())) - { - e.error("slice `%s` is not mutable", e.e1.toChars()); - return new ErrorExp(); - } - if (e.e1.op == TOKarrayliteral) - { - return e.e1.modifiableLvalue(sc, e.e1); - } - - return arrayOp(cast(BinExp)e, sc); -} - -/****************************************** - * Construct the identifier for the array operation function, - * and build the argument list to pass to it. - */ -extern (C++) void buildArrayIdent(Expression e, OutBuffer* buf, Expressions* arguments) -{ - extern (C++) final class BuildArrayIdentVisitor : Visitor - { - alias visit = super.visit; - OutBuffer* buf; - Expressions* arguments; - - public: - extern (D) this(OutBuffer* buf, Expressions* arguments) - { - this.buf = buf; - this.arguments = arguments; - } - - override void visit(Expression e) - { - buf.writestring("Exp"); - arguments.shift(e); - } - - override void visit(CastExp e) - { - Type tb = e.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - e.e1.accept(this); - } - else - visit(cast(Expression)e); - } - - override void visit(ArrayLiteralExp e) - { - buf.writestring("Slice"); - arguments.shift(e); - } - - override void visit(SliceExp e) - { - buf.writestring("Slice"); - arguments.shift(e); - } - - override void visit(AssignExp e) - { - /* Evaluate assign expressions right to left - */ - e.e2.accept(this); - e.e1.accept(this); - buf.writestring("Assign"); - } - - override void visit(BinAssignExp e) - { - /* Evaluate assign expressions right to left - */ - e.e2.accept(this); - e.e1.accept(this); - const(char)* s; - switch (e.op) - { - case TOKaddass: s = "Addass"; break; - case TOKminass: s = "Minass"; break; - case TOKmulass: s = "Mulass"; break; - case TOKdivass: s = "Divass"; break; - case TOKmodass: s = "Modass"; break; - case TOKxorass: s = "Xorass"; break; - case TOKandass: s = "Andass"; break; - case TOKorass: s = "Orass"; break; - case TOKpowass: s = "Powass"; break; - default: - assert(0); - } - buf.writestring(s); - } - - override void visit(NegExp e) - { - e.e1.accept(this); - buf.writestring("Neg"); - } - - override void visit(ComExp e) - { - e.e1.accept(this); - buf.writestring("Com"); - } - - override void visit(BinExp e) - { - /* Evaluate assign expressions left to right - */ - const(char)* s = null; - switch (e.op) - { - case TOKadd: s = "Add"; break; - case TOKmin: s = "Min"; break; - case TOKmul: s = "Mul"; break; - case TOKdiv: s = "Div"; break; - case TOKmod: s = "Mod"; break; - case TOKxor: s = "Xor"; break; - case TOKand: s = "And"; break; - case TOKor: s = "Or"; break; - case TOKpow: s = "Pow"; break; - default: - break; - } - if (s) - { - Type tb = e.type.toBasetype(); - Type t1 = e.e1.type.toBasetype(); - Type t2 = e.e2.type.toBasetype(); - e.e1.accept(this); - if (t1.ty == Tarray && - (t2.ty == Tarray && !t1.equivalent(tb) || - t2.ty != Tarray && !t1.nextOf().equivalent(e.e2.type))) - { - // https://issues.dlang.org/show_bug.cgi?id=12780 - // if A is narrower than B: - // A[] op B[] - // A[] op B - buf.writestring("Of"); - buf.writestring(t1.nextOf().mutableOf().deco); - } - e.e2.accept(this); - if (t2.ty == Tarray && - (t1.ty == Tarray && !t2.equivalent(tb) || - t1.ty != Tarray && !t2.nextOf().equivalent(e.e1.type))) - { - // https://issues.dlang.org/show_bug.cgi?id=12780 - // if B is narrower than A: - // A[] op B[] - // A op B[] - buf.writestring("Of"); - buf.writestring(t2.nextOf().mutableOf().deco); - } - buf.writestring(s); - } - else - visit(cast(Expression)e); - } - } - - scope BuildArrayIdentVisitor v = new BuildArrayIdentVisitor(buf, arguments); - e.accept(v); -} - -/****************************************** - * Construct the inner loop for the array operation function, - * and build the parameter list. - */ -extern (C++) Expression buildArrayLoop(Expression e, Parameters* fparams) -{ - extern (C++) final class BuildArrayLoopVisitor : Visitor - { - alias visit = super.visit; - Parameters* fparams; - Expression result; - - public: - extern (D) this(Parameters* fparams) - { - this.fparams = fparams; - } - - override void visit(Expression e) - { - Identifier id = Identifier.generateId("c", fparams.dim); - auto param = new Parameter(0, e.type, id, null); - fparams.shift(param); - result = new IdentifierExp(Loc(), id); - } - - override void visit(CastExp e) - { - Type tb = e.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - e.e1.accept(this); - } - else - visit(cast(Expression)e); - } - - override void visit(ArrayLiteralExp e) - { - Identifier id = Identifier.generateId("p", fparams.dim); - auto param = new Parameter(STCconst, e.type, id, null); - fparams.shift(param); - Expression ie = new IdentifierExp(Loc(), id); - Expression index = new IdentifierExp(Loc(), Id.p); - result = new ArrayExp(Loc(), ie, index); - } - - override void visit(SliceExp e) - { - Identifier id = Identifier.generateId("p", fparams.dim); - auto param = new Parameter(STCconst, e.type, id, null); - fparams.shift(param); - Expression ie = new IdentifierExp(Loc(), id); - Expression index = new IdentifierExp(Loc(), Id.p); - result = new ArrayExp(Loc(), ie, index); - } - - override void visit(AssignExp e) - { - /* Evaluate assign expressions right to left - */ - Expression ex2 = buildArrayLoop(e.e2); - /* Need the cast because: - * b = c + p[i]; - * where b is a byte fails because (c + p[i]) is an int - * which cannot be implicitly cast to byte. - */ - ex2 = new CastExp(Loc(), ex2, e.e1.type.nextOf()); - Expression ex1 = buildArrayLoop(e.e1); - Parameter param = (*fparams)[0]; - param.storageClass = 0; - result = new AssignExp(Loc(), ex1, ex2); - } - - override void visit(BinAssignExp e) - { - /* Evaluate assign expressions right to left - */ - Expression ex2 = buildArrayLoop(e.e2); - Expression ex1 = buildArrayLoop(e.e1); - Parameter param = (*fparams)[0]; - param.storageClass = 0; - switch (e.op) - { - case TOKaddass: result = new AddAssignExp(e.loc, ex1, ex2); return; - case TOKminass: result = new MinAssignExp(e.loc, ex1, ex2); return; - case TOKmulass: result = new MulAssignExp(e.loc, ex1, ex2); return; - case TOKdivass: result = new DivAssignExp(e.loc, ex1, ex2); return; - case TOKmodass: result = new ModAssignExp(e.loc, ex1, ex2); return; - case TOKxorass: result = new XorAssignExp(e.loc, ex1, ex2); return; - case TOKandass: result = new AndAssignExp(e.loc, ex1, ex2); return; - case TOKorass: result = new OrAssignExp(e.loc, ex1, ex2); return; - case TOKpowass: result = new PowAssignExp(e.loc, ex1, ex2); return; - default: - assert(0); - } - } - - override void visit(NegExp e) - { - Expression ex1 = buildArrayLoop(e.e1); - result = new NegExp(Loc(), ex1); - } - - override void visit(ComExp e) - { - Expression ex1 = buildArrayLoop(e.e1); - result = new ComExp(Loc(), ex1); - } - - override void visit(BinExp e) - { - if (isBinArrayOp(e.op)) - { - /* Evaluate assign expressions left to right - */ - BinExp be = cast(BinExp)e.copy(); - be.e1 = buildArrayLoop(be.e1); - be.e2 = buildArrayLoop(be.e2); - be.type = null; - result = be; - return; - } - else - { - visit(cast(Expression)e); - return; - } - } - - Expression buildArrayLoop(Expression e) - { - e.accept(this); - return result; - } - } - - scope BuildArrayLoopVisitor v = new BuildArrayLoopVisitor(fparams); - return v.buildArrayLoop(e); -} - -/*********************************************** - * Test if expression is a unary array op. - */ -extern (C++) bool isUnaArrayOp(TOK op) -{ - switch (op) - { - case TOKneg: - case TOKtilde: - return true; - default: - break; - } - return false; -} - -/*********************************************** - * Test if expression is a binary array op. - */ -extern (C++) bool isBinArrayOp(TOK op) -{ - switch (op) - { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKpow: - return true; - default: - break; - } - return false; -} - -/*********************************************** - * Test if expression is a binary assignment array op. - */ -extern (C++) bool isBinAssignArrayOp(TOK op) -{ - switch (op) - { - case TOKaddass: - case TOKminass: - case TOKmulass: - case TOKdivass: - case TOKmodass: - case TOKxorass: - case TOKandass: - case TOKorass: - case TOKpowass: - return true; - default: - break; - } - return false; -} - -/*********************************************** - * Test if operand is a valid array op operand. - */ -extern (C++) bool isArrayOpOperand(Expression e) -{ - //printf("Expression.isArrayOpOperand() %s\n", e.toChars()); - if (e.op == TOKslice) - return true; - if (e.op == TOKarrayliteral) - { - Type t = e.type.toBasetype(); - while (t.ty == Tarray || t.ty == Tsarray) - t = t.nextOf().toBasetype(); - return (t.ty != Tvoid); - } - Type tb = e.type.toBasetype(); - if (tb.ty == Tarray) - { - return (isUnaArrayOp(e.op) || - isBinArrayOp(e.op) || - isBinAssignArrayOp(e.op) || - e.op == TOKassign); - } - return false; -} - - -/*************************************************** - * Print error message about invalid array operation. - * Params: - * e = expression with the invalid array operation - * Returns: - * instance of ErrorExp - */ - -ErrorExp arrayOpInvalidError(Expression e) -{ - e.error("invalid array operation `%s` (possible missing [])", e.toChars()); - return new ErrorExp(); -} diff -Nru ldc-1.6.0/ddmd/arraytypes.d ldc-1.8.0/ddmd/arraytypes.d --- ldc-1.6.0/ddmd/arraytypes.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/arraytypes.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/arraytypes.d, _arraytypes.d) - */ - -module ddmd.arraytypes; - -// Online documentation: https://dlang.org/phobos/ddmd_arraytypes.html - -import ddmd.dclass; -import ddmd.declaration; -import ddmd.dmodule; -import ddmd.dsymbol; -import ddmd.dtemplate; -import ddmd.expression; -import ddmd.func; -import ddmd.identifier; -import ddmd.init; -import ddmd.mtype; -import ddmd.root.array; -import ddmd.root.rootobject; -import ddmd.statement; - -alias Strings = Array!(const(char)*); -alias Identifiers = Array!(Identifier); -alias TemplateParameters = Array!(TemplateParameter); -alias Expressions = Array!(Expression); -alias Statements = Array!(Statement); -alias BaseClasses = Array!(BaseClass*); -alias ClassDeclarations = Array!(ClassDeclaration); -alias Dsymbols = Array!(Dsymbol); -alias Objects = Array!(RootObject); -alias FuncDeclarations = Array!(FuncDeclaration); -alias Parameters = Array!(Parameter); -alias Initializers = Array!(Initializer); -alias VarDeclarations = Array!(VarDeclaration); -alias Types = Array!(Type); -alias Catches = Array!(Catch); -alias StaticDtorDeclarations = Array!(StaticDtorDeclaration); -alias SharedStaticDtorDeclarations = Array!(SharedStaticDtorDeclaration); -alias AliasDeclarations = Array!(AliasDeclaration); -alias Modules = Array!(Module); -alias CaseStatements = Array!(CaseStatement); -alias ScopeStatements = Array!(ScopeStatement); -alias GotoCaseStatements = Array!(GotoCaseStatement); -alias ReturnStatements = Array!(ReturnStatement); -alias GotoStatements = Array!(GotoStatement); -alias TemplateInstances = Array!(TemplateInstance); diff -Nru ldc-1.6.0/ddmd/arraytypes.h ldc-1.8.0/ddmd/arraytypes.h --- ldc-1.6.0/ddmd/arraytypes.h 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/arraytypes.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (c) 2006-2014 by Digital Mars - * All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/dlang/dmd/blob/master/src/arraytypes.h - */ - -#ifndef DMD_ARRAYTYPES_H -#define DMD_ARRAYTYPES_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - - -#include "root.h" - -typedef Array TemplateParameters; - -typedef Array Expressions; - -typedef Array Statements; - -typedef Array BaseClasses; - -typedef Array ClassDeclarations; - -typedef Array Dsymbols; - -typedef Array Objects; - -typedef Array FuncDeclarations; - -typedef Array Parameters; - -typedef Array Identifiers; - -typedef Array Initializers; - -typedef Array VarDeclarations; - -typedef Array Types; -typedef Array Catches; - -typedef Array StaticDtorDeclarations; - -typedef Array SharedStaticDtorDeclarations; - -typedef Array AliasDeclarations; - -typedef Array Modules; - -typedef Array Files; - -typedef Array CaseStatements; - -typedef Array ScopeStatements; - -typedef Array GotoCaseStatements; - -typedef Array ReturnStatements; - -typedef Array GotoStatements; - -typedef Array TemplateInstances; - -#endif diff -Nru ldc-1.6.0/ddmd/astcodegen.d ldc-1.8.0/ddmd/astcodegen.d --- ldc-1.6.0/ddmd/astcodegen.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/astcodegen.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -module ddmd.astcodegen; - -// Online documentation: https://dlang.org/phobos/ddmd_astcodegen.html - -struct ASTCodegen -{ - import ddmd.aggregate; - import ddmd.aliasthis; - import ddmd.arraytypes; - import ddmd.attrib; - import ddmd.cond; - import ddmd.dclass; - import ddmd.declaration; - import ddmd.denum; - import ddmd.dimport; - import ddmd.dmodule; - import ddmd.dstruct; - import ddmd.dsymbol; - import ddmd.dtemplate; - import ddmd.dversion; - import ddmd.expression; - import ddmd.func; - import ddmd.hdrgen; - import ddmd.init; - import ddmd.initsem; - import ddmd.mtype; - import ddmd.nspace; - import ddmd.statement; - import ddmd.staticassert; - import ddmd.typesem; - - alias initializerToExpression = ddmd.initsem.initializerToExpression; - alias typeToExpression = ddmd.typesem.typeToExpression; - alias UserAttributeDeclaration = ddmd.attrib.UserAttributeDeclaration; - - alias MODconst = ddmd.mtype.MODconst; - alias MODimmutable = ddmd.mtype.MODimmutable; - alias MODshared = ddmd.mtype.MODshared; - alias MODwild = ddmd.mtype.MODwild; - alias Type = ddmd.mtype.Type; - alias Tident = ddmd.mtype.Tident; - alias Tfunction = ddmd.mtype.Tfunction; - alias Parameter = ddmd.mtype.Parameter; - alias Taarray = ddmd.mtype.Taarray; - alias Tsarray = ddmd.mtype.Tsarray; - - alias STCconst = ddmd.declaration.STCconst; - alias STCimmutable = ddmd.declaration.STCimmutable; - alias STCshared = ddmd.declaration.STCshared; - alias STCwild = ddmd.declaration.STCwild; - alias STCin = ddmd.declaration.STCin; - alias STCout = ddmd.declaration.STCout; - alias STCref = ddmd.declaration.STCref; - alias STClazy = ddmd.declaration.STClazy; - alias STCscope = ddmd.declaration.STCscope; - alias STCfinal = ddmd.declaration.STCfinal; - alias STCauto = ddmd.declaration.STCauto; - alias STCreturn = ddmd.declaration.STCreturn; - alias STCmanifest = ddmd.declaration.STCmanifest; - alias STCgshared = ddmd.declaration.STCgshared; - alias STCtls = ddmd.declaration.STCtls; - alias STCsafe = ddmd.declaration.STCsafe; - alias STCsystem = ddmd.declaration.STCsystem; - alias STCtrusted = ddmd.declaration.STCtrusted; - alias STCnothrow = ddmd.declaration.STCnothrow; - alias STCpure = ddmd.declaration.STCpure; - alias STCproperty = ddmd.declaration.STCproperty; - alias STCnogc = ddmd.declaration.STCnogc; - alias STCdisable = ddmd.declaration.STCdisable; - alias STCundefined = ddmd.declaration.STCundefined; - alias STC_TYPECTOR = ddmd.declaration.STC_TYPECTOR; - alias STCoverride = ddmd.declaration.STCoverride; - alias STCabstract = ddmd.declaration.STCabstract; - alias STCsynchronized = ddmd.declaration.STCsynchronized; - alias STCdeprecated = ddmd.declaration.STCdeprecated; - alias STCstatic = ddmd.declaration.STCstatic; - alias STCextern = ddmd.declaration.STCextern; - alias STCfuture = ddmd.declaration.STCfuture; - alias STCalias = ddmd.declaration.STCalias; - alias STClocal = ddmd.declaration.STClocal; - - alias Dsymbol = ddmd.dsymbol.Dsymbol; - alias Dsymbols = ddmd.dsymbol.Dsymbols; - alias PROTprivate = ddmd.dsymbol.PROTprivate; - alias PROTpackage = ddmd.dsymbol.PROTpackage; - alias PROTprotected = ddmd.dsymbol.PROTprotected; - alias PROTpublic = ddmd.dsymbol.PROTpublic; - alias PROTexport = ddmd.dsymbol.PROTexport; - alias PROTundefined = ddmd.dsymbol.PROTundefined; - alias Prot = ddmd.dsymbol.Prot; - - alias stcToBuffer = ddmd.hdrgen.stcToBuffer; - alias linkageToChars = ddmd.hdrgen.linkageToChars; - alias protectionToChars = ddmd.hdrgen.protectionToChars; -} diff -Nru ldc-1.6.0/ddmd/asttypename.d ldc-1.8.0/ddmd/asttypename.d --- ldc-1.6.0/ddmd/asttypename.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/asttypename.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -/** - * Part of the Compiler implementation of the D programming language - * Copyright: Copyright (c) 1999-2017 by The D Language Foundation, All Rights Reserved - * Authors: Stefan Koch - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/asttypename.d, _asttypename.d) - */ - -module ddmd.asttypename; - -// Online documentation: https://dlang.org/phobos/ddmd_asttypename.html - -import ddmd.attrib; -import ddmd.aliasthis; -import ddmd.aggregate; -import ddmd.complex; -import ddmd.cond; -import ddmd.ctfeexpr; -import ddmd.dclass; -import ddmd.declaration; -import ddmd.denum; -import ddmd.dimport; -import ddmd.declaration; -import ddmd.dstruct; -import ddmd.dsymbol; -import ddmd.dtemplate; -import ddmd.dversion; -import ddmd.expression; -import ddmd.func; -import ddmd.denum; -import ddmd.dimport; -import ddmd.dmodule; -import ddmd.mtype; -import ddmd.typinf; -import ddmd.identifier; -import ddmd.init; -import ddmd.doc; -import ddmd.root.rootobject; -import ddmd.statement; -import ddmd.staticassert; -import ddmd.nspace; -import ddmd.visitor; - -/// Returns: the typename of the dynamic ast-node-type -/// (this is a development tool, do not use in actual code) -string astTypeName(RootObject node) -{ - final switch (node.dyncast()) - { - case DYNCAST.object: - return "RootObject"; - case DYNCAST.identifier: - return "Identifier"; - - case DYNCAST.expression: - return astTypeName(cast(Expression) node); - case DYNCAST.dsymbol: - return astTypeName(cast(Dsymbol) node); - case DYNCAST.type: - return astTypeName(cast(Type) node); - case DYNCAST.tuple: - return astTypeName(cast(Tuple) node); - case DYNCAST.parameter: - return astTypeName(cast(Parameter) node); - case DYNCAST.statement: - return astTypeName(cast(Statement) node); - case DYNCAST.condition: - return astTypeName(cast(Condition) node); - } -} - -mixin -({ - string astTypeNameFunctions; - string visitOverloads; - - foreach (ov; __traits(getOverloads, Visitor, "visit")) - { - static if (is(typeof(ov) P == function)) - { - static if (is(P[0] S == super) && is(S[0] == RootObject)) - { - astTypeNameFunctions ~= ` -string astTypeName(` ~ P[0].stringof ~ ` node) -{ - scope tsv = new AstTypeNameVisitor; - node.accept(tsv); - return tsv.typeName; -} -`; - } - - visitOverloads ~= ` - override void visit (` ~ P[0].stringof ~ ` _) - { - typeName = "` ~ P[0].stringof ~ `"; - } -`; - } - } - - return astTypeNameFunctions ~ ` -extern(C++) final class AstTypeNameVisitor : Visitor -{ - alias visit = super.visit; -public : - string typeName; -` ~ visitOverloads ~ "}"; -}()); - -/// -unittest -{ - import ddmd.globals : Loc; - Expression e = new TypeidExp(Loc.init, null); - assert(e.astTypeName == "TypeidExp"); -} diff -Nru ldc-1.6.0/ddmd/attrib.d ldc-1.8.0/ddmd/attrib.d --- ldc-1.6.0/ddmd/attrib.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/attrib.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,1860 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/attrib.d, _attrib.d) - */ - -module ddmd.attrib; - -// Online documentation: https://dlang.org/phobos/ddmd_attrib.html - -import core.stdc.stdio; -import core.stdc.string; -import ddmd.aggregate; -import ddmd.arraytypes; -import ddmd.astcodegen; -import ddmd.cond; -import ddmd.declaration; -import ddmd.dinterpret; -import ddmd.dmodule; -import ddmd.dscope; -import ddmd.dsymbol; -import ddmd.dtemplate; -import ddmd.errors; -import ddmd.expression; -import ddmd.expressionsem; -import ddmd.func; -import ddmd.globals; -import ddmd.hdrgen; -import ddmd.id; -import ddmd.identifier; -import ddmd.mtype; -import ddmd.parse; -import ddmd.root.outbuffer; -import ddmd.root.rmem; -import ddmd.target; -import ddmd.tokens; -import ddmd.utf; -import ddmd.utils; -import ddmd.visitor; - -version(IN_LLVM) -{ - import gen.dpragma; -} - - -/*********************************************************** - */ -extern (C++) abstract class AttribDeclaration : Dsymbol -{ - Dsymbols* decl; // array of Dsymbol's - - final extern (D) this(Dsymbols* decl) - { - this.decl = decl; - } - - Dsymbols* include(Scope* sc, ScopeDsymbol sds) - { - return decl; - } - - override final int apply(Dsymbol_apply_ft_t fp, void* param) - { - Dsymbols* d = include(_scope, null); - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - if (s) - { - if (s.apply(fp, param)) - return 1; - } - } - } - return 0; - } - - /**************************************** - * Create a new scope if one or more given attributes - * are different from the sc's. - * If the returned scope != sc, the caller should pop - * the scope after it used. - */ - static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage, - CPPMANGLE cppmangle, Prot protection, int explicitProtection, - AlignDeclaration aligndecl, PINLINE inlining) - { - Scope* sc2 = sc; - if (stc != sc.stc || - linkage != sc.linkage || - cppmangle != sc.cppmangle || - !protection.isSubsetOf(sc.protection) || - explicitProtection != sc.explicitProtection || - aligndecl !is sc.aligndecl || - inlining != sc.inlining) - { - // create new one for changes - sc2 = sc.copy(); - sc2.stc = stc; - sc2.linkage = linkage; - sc2.cppmangle = cppmangle; - sc2.protection = protection; - sc2.explicitProtection = explicitProtection; - sc2.aligndecl = aligndecl; - sc2.inlining = inlining; - } - return sc2; - } - - /**************************************** - * A hook point to supply scope for members. - * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this. - */ - Scope* newScope(Scope* sc) - { - return sc; - } - - override void addMember(Scope* sc, ScopeDsymbol sds) - { - Dsymbols* d = include(sc, sds); - if (d) - { - Scope* sc2 = newScope(sc); - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars()); - s.addMember(sc2, sds); - } - if (sc2 != sc) - sc2.pop(); - } - } - - override void setScope(Scope* sc) - { - Dsymbols* d = include(sc, null); - //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d); - if (d) - { - Scope* sc2 = newScope(sc); - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.setScope(sc2); - } - if (sc2 != sc) - sc2.pop(); - } - } - - override void importAll(Scope* sc) - { - Dsymbols* d = include(sc, null); - //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); - if (d) - { - Scope* sc2 = newScope(sc); - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.importAll(sc2); - } - if (sc2 != sc) - sc2.pop(); - } - } - - override void semantic(Scope* sc) - { - if (semanticRun != PASSinit) - return; - semanticRun = PASSsemantic; - Dsymbols* d = include(sc, null); - //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - Scope* sc2 = newScope(sc); - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.semantic(sc2); - } - if (sc2 != sc) - sc2.pop(); - } - semanticRun = PASSsemanticdone; - } - - override void semantic2(Scope* sc) - { - Dsymbols* d = include(sc, null); - if (d) - { - Scope* sc2 = newScope(sc); - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.semantic2(sc2); - } - if (sc2 != sc) - sc2.pop(); - } - } - - override void semantic3(Scope* sc) - { - Dsymbols* d = include(sc, null); - if (d) - { - Scope* sc2 = newScope(sc); - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.semantic3(sc2); - } - if (sc2 != sc) - sc2.pop(); - } - } - - override void addComment(const(char)* comment) - { - //printf("AttribDeclaration::addComment %s\n", comment); - if (comment) - { - Dsymbols* d = include(null, null); - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - //printf("AttribDeclaration::addComment %s\n", s.toChars()); - s.addComment(comment); - } - } - } - } - - override const(char)* kind() const - { - return "attribute"; - } - - override bool oneMember(Dsymbol* ps, Identifier ident) - { - Dsymbols* d = include(null, null); - return Dsymbol.oneMembers(d, ps, ident); - } - - override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) - { - Dsymbols* d = include(null, null); - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.setFieldOffset(ad, poffset, isunion); - } - } - } - - override final bool hasPointers() - { - Dsymbols* d = include(null, null); - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - if (s.hasPointers()) - return true; - } - } - return false; - } - - override final bool hasStaticCtorOrDtor() - { - Dsymbols* d = include(null, null); - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - if (s.hasStaticCtorOrDtor()) - return true; - } - } - return false; - } - - override final void checkCtorConstInit() - { - Dsymbols* d = include(null, null); - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.checkCtorConstInit(); - } - } - } - - /**************************************** - */ - override final void addLocalClass(ClassDeclarations* aclasses) - { - Dsymbols* d = include(null, null); - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.addLocalClass(aclasses); - } - } - } - - override final inout(AttribDeclaration) isAttribDeclaration() inout - { - return this; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) class StorageClassDeclaration : AttribDeclaration -{ - StorageClass stc; - - final extern (D) this(StorageClass stc, Dsymbols* decl) - { - super(decl); - this.stc = stc; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl)); - } - - override Scope* newScope(Scope* sc) - { - StorageClass scstc = sc.stc; - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - if (stc & (STCsafe | STCtrusted | STCsystem)) - scstc &= ~(STCsafe | STCtrusted | STCsystem); - scstc |= stc; - //printf("scstc = x%llx\n", scstc); - return createNewScope(sc, scstc, sc.linkage, sc.cppmangle, - sc.protection, sc.explicitProtection, sc.aligndecl, sc.inlining); - } - - override final bool oneMember(Dsymbol* ps, Identifier ident) - { - bool t = Dsymbol.oneMembers(decl, ps, ident); - if (t && *ps) - { - /* This is to deal with the following case: - * struct Tick { - * template to(T) { const T to() { ... } } - * } - * For eponymous function templates, the 'const' needs to get attached to 'to' - * before the semantic analysis of 'to', so that template overloading based on the - * 'this' pointer can be successful. - */ - FuncDeclaration fd = (*ps).isFuncDeclaration(); - if (fd) - { - /* Use storage_class2 instead of storage_class otherwise when we do .di generation - * we'll wind up with 'const const' rather than 'const'. - */ - /* Don't think we need to worry about mutually exclusive storage classes here - */ - fd.storage_class2 |= stc; - } - } - return t; - } - - override void addMember(Scope* sc, ScopeDsymbol sds) - { - Dsymbols* d = include(sc, sds); - if (d) - { - Scope* sc2 = newScope(sc); - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars()); - // STClocal needs to be attached before the member is added to the scope (because it influences the parent symbol) - if (auto decl = s.isDeclaration()) - { - decl.storage_class |= stc & STClocal; - if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case? - { - sdecl.stc |= stc & STClocal; - } - } - s.addMember(sc2, sds); - } - if (sc2 != sc) - sc2.pop(); - } - - } - - override inout(StorageClassDeclaration) isStorageClassDeclaration() inout - { - return this; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration -{ - Expression msg; - const(char)* msgstr; - - extern (D) this(Expression msg, Dsymbols* decl) - { - super(STCdeprecated, decl); - this.msg = msg; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl)); - } - - /** - * Provides a new scope with `STCdeprecated` and `Scope.depdecl` set - * - * Calls `StorageClassDeclaration.newScope` (as it must be called or copied - * in any function overriding `newScope`), then set the `Scope`'s depdecl. - * - * Returns: - * Always a new scope, to use for this `DeprecatedDeclaration`'s members. - */ - override Scope* newScope(Scope* sc) - { - auto scx = super.newScope(sc); - // The enclosing scope is deprecated as well - if (scx == sc) - scx = sc.push(); - scx.depdecl = this; - return scx; - } - - override void setScope(Scope* sc) - { - //printf("DeprecatedDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol.setScope(sc); // for forward reference - return AttribDeclaration.setScope(sc); - } - - /** - * Run the DeprecatedDeclaration's semantic2 phase then its members. - * - * The message set via a `DeprecatedDeclaration` can be either of: - * - a string literal - * - an enum - * - a static immutable - * So we need to call ctfe to resolve it. - * Afterward forwards to the members' semantic2. - */ - override void semantic2(Scope* sc) - { - getMessage(); - super.semantic2(sc); - } - - const(char)* getMessage() - { - if (auto sc = _scope) - { - _scope = null; - - sc = sc.startCTFE(); - msg = msg.semantic(sc); - msg = resolveProperties(sc, msg); - sc = sc.endCTFE(); - msg = msg.ctfeInterpret(); - - if (auto se = msg.toStringExp()) - msgstr = se.toStringz().ptr; - else - msg.error("compile time constant expected, not `%s`", msg.toChars()); - } - return msgstr; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class LinkDeclaration : AttribDeclaration -{ - LINK linkage; - - extern (D) this(LINK p, Dsymbols* decl) - { - super(decl); - //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = (p == LINKsystem) ? Target.systemLinkage() : p; - } - - static LinkDeclaration create(LINK p, Dsymbols* decl) - { - return new LinkDeclaration(p, decl); - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new LinkDeclaration(linkage, Dsymbol.arraySyntaxCopy(decl)); - } - - override Scope* newScope(Scope* sc) - { - return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, - sc.aligndecl, sc.inlining); - } - - override const(char)* toChars() const - { - return "extern ()"; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class CPPMangleDeclaration : AttribDeclaration -{ - CPPMANGLE cppmangle; - - extern (D) this(CPPMANGLE p, Dsymbols* decl) - { - super(decl); - //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", p, decl); - cppmangle = p; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new CPPMangleDeclaration(cppmangle, Dsymbol.arraySyntaxCopy(decl)); - } - - override Scope* newScope(Scope* sc) - { - return createNewScope(sc, sc.stc, LINKcpp, cppmangle, sc.protection, sc.explicitProtection, - sc.aligndecl, sc.inlining); - } - - override const(char)* toChars() const - { - return "extern ()"; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class ProtDeclaration : AttribDeclaration -{ - Prot protection; - Identifiers* pkg_identifiers; - - /** - * Params: - * loc = source location of attribute token - * p = protection attribute data - * decl = declarations which are affected by this protection attribute - */ - extern (D) this(Loc loc, Prot p, Dsymbols* decl) - { - super(decl); - this.loc = loc; - this.protection = p; - //printf("decl = %p\n", decl); - } - - /** - * Params: - * loc = source location of attribute token - * pkg_identifiers = list of identifiers for a qualified package name - * decl = declarations which are affected by this protection attribute - */ - extern (D) this(Loc loc, Identifiers* pkg_identifiers, Dsymbols* decl) - { - super(decl); - this.loc = loc; - this.protection.kind = PROTpackage; - this.protection.pkg = null; - this.pkg_identifiers = pkg_identifiers; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - if (protection.kind == PROTpackage) - return new ProtDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl)); - else - return new ProtDeclaration(this.loc, protection, Dsymbol.arraySyntaxCopy(decl)); - } - - override Scope* newScope(Scope* sc) - { - if (pkg_identifiers) - semantic(sc); - return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.protection, 1, sc.aligndecl, sc.inlining); - } - - override void addMember(Scope* sc, ScopeDsymbol sds) - { - if (pkg_identifiers) - { - Dsymbol tmp; - Package.resolve(pkg_identifiers, &tmp, null); - protection.pkg = tmp ? tmp.isPackage() : null; - pkg_identifiers = null; - } - if (protection.kind == PROTpackage && protection.pkg && sc._module) - { - Module m = sc._module; - Package pkg = m.parent ? m.parent.isPackage() : null; - if (!pkg || !protection.pkg.isAncestorPackageOf(pkg)) - error("does not bind to one of ancestor packages of module `%s`", m.toPrettyChars(true)); - } - return AttribDeclaration.addMember(sc, sds); - } - - override const(char)* kind() const - { - return "protection attribute"; - } - - override const(char)* toPrettyChars(bool) - { - assert(protection.kind > PROTundefined); - OutBuffer buf; - buf.writeByte('\''); - protectionToBuffer(&buf, protection); - buf.writeByte('\''); - return buf.extractString(); - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class AlignDeclaration : AttribDeclaration -{ - Expression ealign; - private enum structalign_t UNKNOWN = 0; - static assert(STRUCTALIGN_DEFAULT != UNKNOWN); - structalign_t salign = UNKNOWN; - - extern (D) this(Loc loc, Expression ealign, Dsymbols* decl) - { - super(decl); - this.loc = loc; - this.ealign = ealign; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new AlignDeclaration(loc, - ealign.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl)); - } - - override Scope* newScope(Scope* sc) - { - return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, this, sc.inlining); - } - - override void semantic2(Scope* sc) - { - getAlignment(sc); - super.semantic2(sc); - } - - structalign_t getAlignment(Scope* sc) - { - if (salign != UNKNOWN) - return salign; - - if (!ealign) - return salign = STRUCTALIGN_DEFAULT; - - sc = sc.startCTFE(); - ealign = ealign.semantic(sc); - ealign = resolveProperties(sc, ealign); - sc = sc.endCTFE(); - ealign = ealign.ctfeInterpret(); - - if (ealign.op == TOKerror) - return salign = STRUCTALIGN_DEFAULT; - - Type tb = ealign.type.toBasetype(); - auto n = ealign.toInteger(); - - if (n < 1 || n & (n - 1) || structalign_t.max < n || !tb.isintegral()) - { - .error(loc, "alignment must be an integer positive power of 2, not %s", ealign.toChars()); - return salign = STRUCTALIGN_DEFAULT; - } - - return salign = cast(structalign_t)n; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class AnonDeclaration : AttribDeclaration -{ - bool isunion; - int sem; // 1 if successful semantic() - uint anonoffset; // offset of anonymous struct - uint anonstructsize; // size of anonymous struct - uint anonalignsize; // size of anonymous struct for alignment purposes - - extern (D) this(Loc loc, bool isunion, Dsymbols* decl) - { - super(decl); - this.loc = loc; - this.isunion = isunion; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); - } - - override void setScope(Scope* sc) - { - if (decl) - Dsymbol.setScope(sc); - return AttribDeclaration.setScope(sc); - } - - override void semantic(Scope* sc) - { - //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); - assert(sc.parent); - auto p = sc.parent.pastMixin(); - auto ad = p.isAggregateDeclaration(); - if (!ad) - { - .error(loc, "%s can only be a part of an aggregate, not %s `%s`", kind(), p.kind(), p.toChars()); - return; - } - - if (decl) - { - sc = sc.push(); - sc.stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); - sc.inunion = isunion; - sc.flags = 0; - for (size_t i = 0; i < decl.dim; i++) - { - Dsymbol s = (*decl)[i]; - s.semantic(sc); - } - sc = sc.pop(); - } - } - - override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) - { - //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); - if (decl) - { - /* This works by treating an AnonDeclaration as an aggregate 'member', - * so in order to place that member we need to compute the member's - * size and alignment. - */ - size_t fieldstart = ad.fields.dim; - - /* Hackishly hijack ad's structsize and alignsize fields - * for use in our fake anon aggregate member. - */ - uint savestructsize = ad.structsize; - uint savealignsize = ad.alignsize; - ad.structsize = 0; - ad.alignsize = 0; - - uint offset = 0; - for (size_t i = 0; i < decl.dim; i++) - { - Dsymbol s = (*decl)[i]; - s.setFieldOffset(ad, &offset, this.isunion); - if (this.isunion) - offset = 0; - } - - /* https://issues.dlang.org/show_bug.cgi?id=13613 - * If the fields in this.members had been already - * added in ad.fields, just update *poffset for the subsequent - * field offset calculation. - */ - if (fieldstart == ad.fields.dim) - { - ad.structsize = savestructsize; - ad.alignsize = savealignsize; - *poffset = ad.structsize; - return; - } - - anonstructsize = ad.structsize; - anonalignsize = ad.alignsize; - ad.structsize = savestructsize; - ad.alignsize = savealignsize; - - // 0 sized structs are set to 1 byte - if (anonstructsize == 0) - { - anonstructsize = 1; - anonalignsize = 1; - } - - assert(_scope); - auto alignment = _scope.alignment(); - - /* Given the anon 'member's size and alignment, - * go ahead and place it. - */ - anonoffset = AggregateDeclaration.placeField( - poffset, - anonstructsize, anonalignsize, alignment, - &ad.structsize, &ad.alignsize, - isunion); - - // Add to the anon fields the base offset of this anonymous aggregate - //printf("anon fields, anonoffset = %d\n", anonoffset); - for (size_t i = fieldstart; i < ad.fields.dim; i++) - { - VarDeclaration v = ad.fields[i]; - //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); - v.offset += anonoffset; - } - } - } - - override const(char)* kind() const - { - return (isunion ? "anonymous union" : "anonymous struct"); - } - - override final inout(AnonDeclaration) isAnonDeclaration() inout - { - return this; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class PragmaDeclaration : AttribDeclaration -{ - Expressions* args; // array of Expression's - - extern (D) this(Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) - { - super(decl); - this.loc = loc; - this.ident = ident; - this.args = args; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); - assert(!s); - return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl)); - } - - override Scope* newScope(Scope* sc) - { - if (ident == Id.Pinline) - { - PINLINE inlining = PINLINEdefault; - if (!args || args.dim == 0) - inlining = PINLINEdefault; - else if (args.dim != 1) - { - error("one boolean expression expected for `pragma(inline)`, not %d", args.dim); - args.setDim(1); - (*args)[0] = new ErrorExp(); - } - else - { - Expression e = (*args)[0]; - if (e.op != TOKint64 || !e.type.equals(Type.tbool)) - { - if (e.op != TOKerror) - { - error("pragma(`inline`, `true` or `false`) expected, not `%s`", e.toChars()); - (*args)[0] = new ErrorExp(); - } - } - else if (e.isBool(true)) - inlining = PINLINEalways; - else if (e.isBool(false)) - inlining = PINLINEnever; - } - return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, inlining); - } - else if (IN_LLVM && ident == Id.LDC_profile_instr) { - bool emitInstr = true; - if (!args || args.dim != 1 || !DtoCheckProfileInstrPragma((*args)[0], emitInstr)) { - error("pragma(LDC_profile_instr, true or false) expected"); - (*args)[0] = new ErrorExp(); - } else { - // Only create a new scope if the emitInstrumentation flag is changed - if (sc.emitInstrumentation != emitInstr) { - auto newscope = sc.copy(); - newscope.emitInstrumentation = emitInstr; - return newscope; - } - } - } - - return sc; - } - - override void semantic(Scope* sc) - { - // Should be merged with PragmaStatement - //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); - - version(IN_LLVM) - { - LDCPragma llvm_internal = LDCPragma.LLVMnone; - const(char)* arg1str = null; - } - - if (ident == Id.msg) - { - if (args) - { - for (size_t i = 0; i < args.dim; i++) - { - Expression e = (*args)[i]; - sc = sc.startCTFE(); - e = e.semantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - // pragma(msg) is allowed to contain types as well as expressions - e = ctfeInterpretForPragmaMsg(e); - if (e.op == TOKerror) - { - errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i].toChars()); - return; - } - StringExp se = e.toStringExp(); - if (se) - { - se = se.toUTF8(sc); - fprintf(stderr, "%.*s", cast(int)se.len, se.string); - } - else - fprintf(stderr, "%s", e.toChars()); - } - fprintf(stderr, "\n"); - } - goto Lnodecl; - } - else if (ident == Id.lib) - { - if (!args || args.dim != 1) - error("string expected for library name"); - else - { - auto se = semanticString(sc, (*args)[0], "library name"); - if (!se) - goto Lnodecl; - (*args)[0] = se; - - auto name = cast(char*)mem.xmalloc(se.len + 1); - memcpy(name, se.string, se.len); - name[se.len] = 0; - if (global.params.verbose) - fprintf(global.stdmsg, "library %s\n", name); - if (global.params.moduleDeps && !global.params.moduleDepsFile) - { - OutBuffer* ob = global.params.moduleDeps; - Module imod = sc.instantiatingModule(); - ob.writestring("depsLib "); - ob.writestring(imod.toPrettyChars()); - ob.writestring(" ("); - escapePath(ob, imod.srcfile.toChars()); - ob.writestring(") : "); - ob.writestring(name); - ob.writenl(); - } - mem.xfree(name); - } - goto Lnodecl; - } - else if (ident == Id.startaddress) - { - if (!args || args.dim != 1) - error("function name expected for start address"); - else - { - /* https://issues.dlang.org/show_bug.cgi?id=11980 - * resolveProperties and ctfeInterpret call are not necessary. - */ - Expression e = (*args)[0]; - sc = sc.startCTFE(); - e = e.semantic(sc); - sc = sc.endCTFE(); - (*args)[0] = e; - Dsymbol sa = getDsymbol(e); - if (!sa || !sa.isFuncDeclaration()) - error("function name expected for start address, not `%s`", e.toChars()); - } - goto Lnodecl; - } - else if (ident == Id.Pinline) - { - goto Ldecl; - } - else if (ident == Id.mangle) - { - if (!args) - args = new Expressions(); - if (args.dim != 1) - { - error("string expected for mangled name"); - args.setDim(1); - (*args)[0] = new ErrorExp(); // error recovery - goto Ldecl; - } - - auto se = semanticString(sc, (*args)[0], "mangled name"); - if (!se) - goto Ldecl; - (*args)[0] = se; // Will be used later - - if (!se.len) - { - error("zero-length string not allowed for mangled name"); - goto Ldecl; - } - if (se.sz != 1) - { - error("mangled name characters can only be of type char"); - goto Ldecl; - } - version (all) - { - /* Note: D language specification should not have any assumption about backend - * implementation. Ideally pragma(mangle) can accept a string of any content. - * - * Therefore, this validation is compiler implementation specific. - */ - for (size_t i = 0; i < se.len;) - { - char* p = se.string; - dchar c = p[i]; - if (c < 0x80) - { - if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c != 0 && strchr("$%().:?@[]_", c)) - { - ++i; - continue; - } - else - { - error("char 0x%02x not allowed in mangled name", c); - break; - } - } - if (const msg = utf_decodeChar(se.string, se.len, i, c)) - { - error("%s", msg); - break; - } - if (!isUniAlpha(c)) - { - error("char `0x%04x` not allowed in mangled name", c); - break; - } - } - } - } - // IN_LLVM - else if ((llvm_internal = DtoGetPragma(sc, this, arg1str)) != LDCPragma.LLVMnone) - { - // nothing to do anymore - } - else if (global.params.ignoreUnsupportedPragmas) - { - if (global.params.verbose) - { - /* Print unrecognized pragmas - */ - fprintf(global.stdmsg, "pragma %s", ident.toChars()); - if (args) - { - for (size_t i = 0; i < args.dim; i++) - { - Expression e = (*args)[i]; - version(IN_LLVM) - { - // ignore errors in ignored pragmas. - global.gag++; - uint errors_save = global.errors; - } - sc = sc.startCTFE(); - e = e.semantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = e.ctfeInterpret(); - if (i == 0) - fprintf(global.stdmsg, " ("); - else - fprintf(global.stdmsg, ","); - fprintf(global.stdmsg, "%s", e.toChars()); - version(IN_LLVM) - { - // restore error state. - global.gag--; - global.errors = errors_save; - } - } - if (args.dim) - fprintf(global.stdmsg, ")"); - } - fprintf(global.stdmsg, "\n"); - } - static if (!IN_LLVM) - goto Lnodecl; } - else - error("unrecognized `pragma(%s)`", ident.toChars()); - Ldecl: - if (decl) - { - Scope* sc2 = newScope(sc); - for (size_t i = 0; i < decl.dim; i++) - { - Dsymbol s = (*decl)[i]; - s.semantic(sc2); - if (ident == Id.mangle) - { - assert(args && args.dim == 1); - if (auto se = (*args)[0].toStringExp()) - { - char* name = cast(char*)mem.xmalloc(se.len + 1); - memcpy(name, se.string, se.len); - name[se.len] = 0; - uint cnt = setMangleOverride(s, name); - if (cnt > 1) - error("can only apply to a single declaration"); - } - } - // IN_LLVM: add else clause - else - { - DtoCheckPragma(this, s, llvm_internal, arg1str); - } - } - if (sc2 != sc) - sc2.pop(); - } - return; - Lnodecl: - if (decl) - { - error("pragma is missing closing `;`"); - goto Ldecl; - // do them anyway, to avoid segfaults. - } - } - - override const(char)* kind() const - { - return "pragma"; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) class ConditionalDeclaration : AttribDeclaration -{ - Condition condition; - Dsymbols* elsedecl; // array of Dsymbol's for else block - - final extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl) - { - super(decl); - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this.condition = condition; - this.elsedecl = elsedecl; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new ConditionalDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); - } - - override final bool oneMember(Dsymbol* ps, Identifier ident) - { - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc); - if (condition.inc) - { - Dsymbols* d = condition.include(null, null) ? decl : elsedecl; - return Dsymbol.oneMembers(d, ps, ident); - } - else - { - bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null); - *ps = null; - return res; - } - } - - // Decide if 'then' or 'else' code should be included - override Dsymbols* include(Scope* sc, ScopeDsymbol sds) - { - //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope); - assert(condition); - return condition.include(_scope ? _scope : sc, sds) ? decl : elsedecl; - } - - override final void addComment(const(char)* comment) - { - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - if (comment) - { - Dsymbols* d = decl; - for (int j = 0; j < 2; j++) - { - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - //printf("ConditionalDeclaration::addComment %s\n", s.toChars()); - s.addComment(comment); - } - } - d = elsedecl; - } - } - } - - override void setScope(Scope* sc) - { - Dsymbols* d = include(sc, null); - //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d); - if (d) - { - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.setScope(sc); - } - } - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class StaticIfDeclaration : ConditionalDeclaration -{ - ScopeDsymbol scopesym; - bool addisdone; - - extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl) - { - super(condition, decl, elsedecl); - //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new StaticIfDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); - } - - /**************************************** - * Different from other AttribDeclaration subclasses, include() call requires - * the completion of addMember and setScope phases. - */ - override Dsymbols* include(Scope* sc, ScopeDsymbol sds) - { - //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope); - if (condition.inc == 0) - { - assert(scopesym); // addMember is already done - assert(_scope); // setScope is already done - Dsymbols* d = ConditionalDeclaration.include(_scope, scopesym); - if (d && !addisdone) - { - // Add members lazily. - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.addMember(_scope, scopesym); - } - // Set the member scopes lazily. - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.setScope(_scope); - } - addisdone = true; - } - return d; - } - else - { - return ConditionalDeclaration.include(sc, scopesym); - } - } - - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("StaticIfDeclaration::addMember() '%s'\n", toChars()); - /* This is deferred until the condition evaluated later (by the include() call), - * so that expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this.scopesym = sds; - } - - override void setScope(Scope* sc) - { - // do not evaluate condition before semantic pass - // But do set the scope, in case we need it for forward referencing - Dsymbol.setScope(sc); - } - - override void importAll(Scope* sc) - { - // do not evaluate condition before semantic pass - } - - override void semantic(Scope* sc) - { - AttribDeclaration.semantic(sc); - } - - override const(char)* kind() const - { - return "static if"; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - * Static foreach at declaration scope, like: - * static foreach (i; [0, 1, 2]){ } - */ - -extern (C++) final class StaticForeachDeclaration : AttribDeclaration -{ - StaticForeach sfe; /// contains `static foreach` expansion logic - - ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration) - - /++ - `include` can be called multiple times, but a `static foreach` - should be expanded at most once. Achieved by caching the result - of the first call. We need both `cached` and `cache`, because - `null` is a valid value for `cache`. - +/ - bool cached = false; - Dsymbols* cache = null; - - extern (D) this(StaticForeach sfe, Dsymbols* decl) - { - super(decl); - this.sfe = sfe; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - return new StaticForeachDeclaration( - sfe.syntaxCopy(), - Dsymbol.arraySyntaxCopy(decl)); - } - - override final bool oneMember(Dsymbol* ps, Identifier ident) - { - // Required to support IFTI on a template that contains a - // `static foreach` declaration. `super.oneMember` calls - // include with a `null` scope. As `static foreach` requires - // the scope for expansion, `oneMember` can only return a - // precise result once `static foreach` has been expanded. - if (cached) - { - return super.oneMember(ps, ident); - } - *ps = null; // a `static foreach` declaration may in general expand to multiple symbols - return false; - } - - override Dsymbols* include(Scope* sc, ScopeDsymbol sds) - { - if (cached) - { - return cache; - } - sfe.prepare(_scope); // lower static foreach aggregate - if (!sfe.ready()) - { - return null; // TODO: ok? - } - - // expand static foreach - import ddmd.statementsem: makeTupleForeach; - Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion); - if (d) // process generated declarations - { - // Add members lazily. - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.addMember(_scope, scopesym); - } - // Set the member scopes lazily. - for (size_t i = 0; i < d.dim; i++) - { - Dsymbol s = (*d)[i]; - s.setScope(_scope); - } - } - cached = true; - cache = d; - return d; - } - - override void addMember(Scope* sc, ScopeDsymbol sds) - { - // used only for caching the enclosing symbol - this.scopesym = sds; - } - - override final void addComment(const(char)* comment) - { - // do nothing - // change this to give semantics to documentation comments on static foreach declarations - } - - override void setScope(Scope* sc) - { - // do not evaluate condition before semantic pass - // But do set the scope, in case we need it for forward referencing - Dsymbol.setScope(sc); - } - - override void importAll(Scope* sc) - { - // do not evaluate aggregate before semantic pass - } - - override void semantic(Scope* sc) - { - AttribDeclaration.semantic(sc); - } - - override const(char)* kind() const - { - return "static foreach"; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - * Collection of declarations that stores foreach index variables in a - * local symbol table. Other symbols declared within are forwarded to - * another scope, like: - * - * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict. - * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STClocal - * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable - * } - * - * static foreach (i; 0.. 10) - * { - * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope - * } - * - * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop - * - * A StaticForeachDeclaration generates one - * ForwardingAttribDeclaration for each expansion of its body. The - * AST of the ForwardingAttribDeclaration contains both the `static - * foreach` variables and the respective copy of the `static foreach` - * body. The functionality is achieved by using a - * ForwardingScopeDsymbol as the parent symbol for the generated - * declarations. - */ - -extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration -{ - ForwardingScopeDsymbol sym = null; - - this(Dsymbols* decl) - { - super(decl); - sym = new ForwardingScopeDsymbol(null); - sym.symtab = new DsymbolTable(); - } - - /************************************** - * Use the ForwardingScopeDsymbol as the parent symbol for members. - */ - override Scope* newScope(Scope* sc) - { - return sc.push(sym); - } - - /*************************************** - * Lazily initializes the scope to forward to. - */ - override void addMember(Scope* sc, ScopeDsymbol sds) - { - parent = sym.parent = sym.forward = sds; - return super.addMember(sc, sym); - } - - override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout - { - return this; - } -} - - -/*********************************************************** - * Mixin declarations, like: - * mixin("int x"); - */ -extern (C++) final class CompileDeclaration : AttribDeclaration -{ - Expression exp; - ScopeDsymbol scopesym; - bool compiled; - - extern (D) this(Loc loc, Expression exp) - { - super(null); - //printf("CompileDeclaration(loc = %d)\n", loc.linnum); - this.loc = loc; - this.exp = exp; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - return new CompileDeclaration(loc, exp.syntaxCopy()); - } - - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); - this.scopesym = sds; - } - - override void setScope(Scope* sc) - { - Dsymbol.setScope(sc); - } - - void compileIt(Scope* sc) - { - //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp.toChars()); - auto se = semanticString(sc, exp, "argument to mixin"); - if (!se) - return; - se = se.toUTF8(sc); - - uint errors = global.errors; - scope p = new Parser!ASTCodegen(loc, sc._module, se.toStringz(), false); - p.nextToken(); - - decl = p.parseDeclDefs(0); - if (p.token.value != TOKeof) - exp.error("incomplete mixin declaration `%s`", se.toChars()); - if (p.errors) - { - assert(global.errors != errors); - decl = null; - } - } - - override void semantic(Scope* sc) - { - //printf("CompileDeclaration::semantic()\n"); - if (!compiled) - { - compileIt(sc); - AttribDeclaration.addMember(sc, scopesym); - compiled = true; - - if (_scope && decl) - { - for (size_t i = 0; i < decl.dim; i++) - { - Dsymbol s = (*decl)[i]; - s.setScope(_scope); - } - } - } - AttribDeclaration.semantic(sc); - } - - override const(char)* kind() const - { - return "mixin"; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - * User defined attributes look like: - * @(args, ...) - */ -extern (C++) final class UserAttributeDeclaration : AttribDeclaration -{ - Expressions* atts; - - extern (D) this(Expressions* atts, Dsymbols* decl) - { - super(decl); - //printf("UserAttributeDeclaration()\n"); - this.atts = atts; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars()); - assert(!s); - return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl)); - } - - override Scope* newScope(Scope* sc) - { - Scope* sc2 = sc; - if (atts && atts.dim) - { - // create new one for changes - sc2 = sc.copy(); - sc2.userAttribDecl = this; - } - return sc2; - } - - override void setScope(Scope* sc) - { - //printf("UserAttributeDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol.setScope(sc); // for forward reference of UDAs - return AttribDeclaration.setScope(sc); - } - - override void semantic(Scope* sc) - { - //printf("UserAttributeDeclaration::semantic() %p\n", this); - if (decl && !_scope) - Dsymbol.setScope(sc); // for function local symbols - return AttribDeclaration.semantic(sc); - } - - override void semantic2(Scope* sc) - { - if (decl && atts && atts.dim && _scope) - { - static void eval(Scope* sc, Expressions* exps) - { - foreach (ref Expression e; *exps) - { - if (e) - { - e = e.semantic(sc); - if (definitelyValueParameter(e)) - e = e.ctfeInterpret(); - if (e.op == TOKtuple) - { - TupleExp te = cast(TupleExp)e; - eval(sc, te.exps); - } - } - } - } - - _scope = null; - eval(sc, atts); - } - AttribDeclaration.semantic2(sc); - } - - static Expressions* concat(Expressions* udas1, Expressions* udas2) - { - Expressions* udas; - if (!udas1 || udas1.dim == 0) - udas = udas2; - else if (!udas2 || udas2.dim == 0) - udas = udas1; - else - { - /* Create a new tuple that combines them - * (do not append to left operand, as this is a copy-on-write operation) - */ - udas = new Expressions(); - udas.push(new TupleExp(Loc(), udas1)); - udas.push(new TupleExp(Loc(), udas2)); - } - return udas; - } - - Expressions* getAttributes() - { - if (auto sc = _scope) - { - _scope = null; - arrayExpressionSemantic(atts, sc); - } - auto exps = new Expressions(); - if (userAttribDecl) - exps.push(new TupleExp(Loc(), userAttribDecl.getAttributes())); - if (atts && atts.dim) - exps.push(new TupleExp(Loc(), atts)); - return exps; - } - - override const(char)* kind() const - { - return "UserAttribute"; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -extern (C++) static uint setMangleOverride(Dsymbol s, char* sym) -{ - AttribDeclaration ad = s.isAttribDeclaration(); - if (ad) - { - Dsymbols* decls = ad.include(null, null); - uint nestedCount = 0; - if (decls && decls.dim) - for (size_t i = 0; i < decls.dim; ++i) - nestedCount += setMangleOverride((*decls)[i], sym); - return nestedCount; - } - else if (s.isFuncDeclaration() || s.isVarDeclaration()) - { - s.isDeclaration().mangleOverride = sym; - return 1; - } - else - return 0; -} diff -Nru ldc-1.6.0/ddmd/attrib.h ldc-1.8.0/ddmd/attrib.h --- ldc-1.6.0/ddmd/attrib.h 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/attrib.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,270 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (c) 1999-2016 by Digital Mars - * All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/dlang/dmd/blob/master/src/attrib.h - */ - -#ifndef DMD_ATTRIB_H -#define DMD_ATTRIB_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -class Expression; -class Statement; -class LabelDsymbol; -class Initializer; -class Module; -class Condition; -class StaticForeach; - -/**************************************************************/ - -class AttribDeclaration : public Dsymbol -{ -public: - Dsymbols *decl; // array of Dsymbol's - - virtual Dsymbols *include(Scope *sc, ScopeDsymbol *sds); - int apply(Dsymbol_apply_ft_t fp, void *param); - static Scope *createNewScope(Scope *sc, - StorageClass newstc, LINK linkage, CPPMANGLE cppmangle, Prot protection, - int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining); - virtual Scope *newScope(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope *sc); - void importAll(Scope *sc); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void addComment(const utf8_t *comment); - const char *kind(); - bool oneMember(Dsymbol **ps, Identifier *ident); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - bool hasPointers(); - bool hasStaticCtorOrDtor(); - void checkCtorConstInit(); - void addLocalClass(ClassDeclarations *); - AttribDeclaration *isAttribDeclaration() { return this; } - - void accept(Visitor *v) { v->visit(this); } -}; - -class StorageClassDeclaration : public AttribDeclaration -{ -public: - StorageClass stc; - - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - bool oneMember(Dsymbol **ps, Identifier *ident); - void addMember(Scope *sc, ScopeDsymbol *sds); - StorageClassDeclaration *isStorageClassDeclaration() { return this; } - - void accept(Visitor *v) { v->visit(this); } -}; - -class DeprecatedDeclaration : public StorageClassDeclaration -{ -public: - Expression *msg; - const char *msgstr; - - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void setScope(Scope *sc); - void semantic2(Scope *sc); - const char *getMessage(); - void accept(Visitor *v) { v->visit(this); } -}; - -class LinkDeclaration : public AttribDeclaration -{ -public: - LINK linkage; - - static LinkDeclaration *create(LINK p, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - const char *toChars(); - void accept(Visitor *v) { v->visit(this); } -}; - -class CPPMangleDeclaration : public AttribDeclaration -{ -public: - CPPMANGLE cppmangle; - - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - const char *toChars(); - void accept(Visitor *v) { v->visit(this); } -}; - -class ProtDeclaration : public AttribDeclaration -{ -public: - Prot protection; - Identifiers* pkg_identifiers; - - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds); - const char *kind(); - const char *toPrettyChars(bool unused); - void accept(Visitor *v) { v->visit(this); } -}; - -class AlignDeclaration : public AttribDeclaration -{ -public: - Expression *ealign; - structalign_t salign; - - AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void setScope(Scope *sc); - void semantic2(Scope *sc); - structalign_t getAlignment(); - void accept(Visitor *v) { v->visit(this); } -}; - -class AnonDeclaration : public AttribDeclaration -{ -public: - bool isunion; - int sem; // 1 if successful semantic() - unsigned anonoffset; // offset of anonymous struct - unsigned anonstructsize; // size of anonymous struct - unsigned anonalignsize; // size of anonymous struct for alignment purposes - - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - const char *kind(); - AnonDeclaration *isAnonDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } -}; - -class PragmaDeclaration : public AttribDeclaration -{ -public: - Expressions *args; // array of Expression's - - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void semantic(Scope *sc); - const char *kind(); - void accept(Visitor *v) { v->visit(this); } -}; - -class ConditionalDeclaration : public AttribDeclaration -{ -public: - Condition *condition; - Dsymbols *elsedecl; // array of Dsymbol's for else block - - Dsymbol *syntaxCopy(Dsymbol *s); - bool oneMember(Dsymbol **ps, Identifier *ident); - Dsymbols *include(Scope *sc, ScopeDsymbol *sds); - void addComment(const utf8_t *comment); - void setScope(Scope *sc); - void accept(Visitor *v) { v->visit(this); } -}; - -class StaticIfDeclaration : public ConditionalDeclaration -{ -public: - ScopeDsymbol *scopesym; - bool addisdone; - - Dsymbol *syntaxCopy(Dsymbol *s); - Dsymbols *include(Scope *sc, ScopeDsymbol *sds); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope *sc); - void importAll(Scope *sc); - void semantic(Scope *sc); - const char *kind(); - void accept(Visitor *v) { v->visit(this); } -}; - -class StaticForeachDeclaration : public ConditionalDeclaration -{ -public: - StaticForeach *sfe; - ScopeDsymbol *scopesym; - bool cached; - Dsymbols *cache; - - Dsymbol *syntaxCopy(Dsymbol *s); - bool oneMember(Dsymbol *ps, Identifier *ident); - Dsymbols *include(Scope *sc, ScopeDsymbol *sds); - void addMember(Scope *sc, ScopeDsymbol *sds); - void addComment(const char *comment); - void setScope(Scope *sc); - void importAll(Scope *sc); - void semantic(Scope *sc); - const char *kind() const; - void accept(Visitor *v) { v->visit(this); } -}; - -class ForwardingAttribDeclaration : AttribDeclaration -{ -public: - ForwardingScopeDsymbol *sym; - - Scope *newScope(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds); - ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; } -}; - -// Mixin declarations - -class CompileDeclaration : public AttribDeclaration -{ -public: - Expression *exp; - - ScopeDsymbol *scopesym; - bool compiled; - - Dsymbol *syntaxCopy(Dsymbol *s); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope *sc); - void compileIt(Scope *sc); - void semantic(Scope *sc); - const char *kind(); - void accept(Visitor *v) { v->visit(this); } -}; - -/** - * User defined attributes look like: - * @(args, ...) - */ -class UserAttributeDeclaration : public AttribDeclaration -{ -public: - Expressions *atts; - - Dsymbol *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void setScope(Scope *sc); - void semantic(Scope *sc); - void semantic2(Scope *sc); - static Expressions *concat(Expressions *udas1, Expressions *udas2); - Expressions *getAttributes(); - const char *kind(); - void accept(Visitor *v) { v->visit(this); } -}; - -#endif /* DMD_ATTRIB_H */ diff -Nru ldc-1.6.0/ddmd/blockexit.d ldc-1.8.0/ddmd/blockexit.d --- ldc-1.6.0/ddmd/blockexit.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/blockexit.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,552 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/blockexit.d, _blockexit.d) - */ - -module ddmd.blockexit; - -// Online documentation: https://dlang.org/phobos/ddmd_blockexit.html - -import core.stdc.stdio; - -import ddmd.arraytypes; -import ddmd.canthrow; -import ddmd.dclass; -import ddmd.declaration; -import ddmd.expression; -import ddmd.func; -import ddmd.globals; -import ddmd.id; -import ddmd.identifier; -import ddmd.mtype; -import ddmd.statement; -import ddmd.tokens; -import ddmd.visitor; - -/** - * BE stands for BlockExit. - * - * It indicates if a statement does transfer control to another block. - * A block is a sequence of statements enclosed in { } - */ -enum BE : int -{ - BEnone = 0, - BEfallthru = 1, - BEthrow = 2, - BEreturn = 4, - BEgoto = 8, - BEhalt = 0x10, - BEbreak = 0x20, - BEcontinue = 0x40, - BEerrthrow = 0x80, - BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), -} - -alias BEnone = BE.BEnone; -alias BEfallthru = BE.BEfallthru; -alias BEthrow = BE.BEthrow; -alias BEreturn = BE.BEreturn; -alias BEgoto = BE.BEgoto; -alias BEhalt = BE.BEhalt; -alias BEbreak = BE.BEbreak; -alias BEcontinue = BE.BEcontinue; -alias BEerrthrow = BE.BEerrthrow; -alias BEany = BE.BEany; - - - -/********************************************* - * Only valid after semantic analysis - * Params: - * mustNotThrow = generate an error if it throws - * Returns: - * BExxxx - */ -int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) -{ - extern (C++) final class BlockExit : Visitor - { - alias visit = super.visit; - public: - FuncDeclaration func; - bool mustNotThrow; - int result; - - extern (D) this(FuncDeclaration func, bool mustNotThrow) - { - this.func = func; - this.mustNotThrow = mustNotThrow; - result = BEnone; - } - - override void visit(Statement s) - { - printf("Statement::blockExit(%p)\n", s); - printf("%s\n", s.toChars()); - assert(0); - } - - override void visit(ErrorStatement s) - { - result = BEany; - } - - override void visit(ExpStatement s) - { - result = BEfallthru; - if (s.exp) - { - if (s.exp.op == TOKhalt) - { - result = BEhalt; - return; - } - if (s.exp.op == TOKassert) - { - AssertExp a = cast(AssertExp)s.exp; - if (a.e1.isBool(false)) // if it's an assert(0) - { - result = BEhalt; - return; - } - } - if (canThrow(s.exp, func, mustNotThrow)) - result |= BEthrow; - } - } - - override void visit(CompileStatement s) - { - assert(global.errors); - result = BEfallthru; - } - - override void visit(CompoundStatement cs) - { - //printf("CompoundStatement.blockExit(%p) %d result = x%X\n", cs, cs.statements.dim, result); - result = BEfallthru; - Statement slast = null; - foreach (s; *cs.statements) - { - if (s) - { - //printf("result = x%x\n", result); - //printf("s: %s\n", s.toChars()); - if (result & BEfallthru && slast) - { - slast = slast.last(); - if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement())) - { - // Allow if last case/default was empty - CaseStatement sc = slast.isCaseStatement(); - DefaultStatement sd = slast.isDefaultStatement(); - if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement())) - { - } - else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement())) - { - } - else - { - const(char)* gototype = s.isCaseStatement() ? "case" : "default"; - s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype); - } - } - } - - if (!(result & BEfallthru) && !s.comeFrom()) - { - if (blockExit(s, func, mustNotThrow) != BEhalt && s.hasCode()) - s.warning("statement is not reachable"); - } - else - { - result &= ~BEfallthru; - result |= blockExit(s, func, mustNotThrow); - } - slast = s; - } - } - } - - override void visit(UnrolledLoopStatement uls) - { - result = BEfallthru; - foreach (s; *uls.statements) - { - if (s) - { - int r = blockExit(s, func, mustNotThrow); - result |= r & ~(BEbreak | BEcontinue | BEfallthru); - if ((r & (BEfallthru | BEcontinue | BEbreak)) == 0) - result &= ~BEfallthru; - } - } - } - - override void visit(ScopeStatement s) - { - //printf("ScopeStatement::blockExit(%p)\n", s.statement); - result = blockExit(s.statement, func, mustNotThrow); - } - - override void visit(ForwardingStatement s) - { - if (s.statement) - { - s.statement.accept(this); - } - else - { - result = BEfallthru; - } - } - - override void visit(WhileStatement s) - { - assert(global.errors); - result = BEfallthru; - } - - override void visit(DoStatement s) - { - if (s._body) - { - result = blockExit(s._body, func, mustNotThrow); - if (result == BEbreak) - { - result = BEfallthru; - return; - } - if (result & BEcontinue) - result |= BEfallthru; - } - else - result = BEfallthru; - if (result & BEfallthru) - { - if (canThrow(s.condition, func, mustNotThrow)) - result |= BEthrow; - if (!(result & BEbreak) && s.condition.isBool(true)) - result &= ~BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - } - - override void visit(ForStatement s) - { - result = BEfallthru; - if (s._init) - { - result = blockExit(s._init, func, mustNotThrow); - if (!(result & BEfallthru)) - return; - } - if (s.condition) - { - if (canThrow(s.condition, func, mustNotThrow)) - result |= BEthrow; - if (s.condition.isBool(true)) - result &= ~BEfallthru; - else if (s.condition.isBool(false)) - return; - } - else - result &= ~BEfallthru; // the body must do the exiting - if (s._body) - { - int r = blockExit(s._body, func, mustNotThrow); - if (r & (BEbreak | BEgoto)) - result |= BEfallthru; - result |= r & ~(BEfallthru | BEbreak | BEcontinue); - } - if (s.increment && canThrow(s.increment, func, mustNotThrow)) - result |= BEthrow; - } - - override void visit(ForeachStatement s) - { - result = BEfallthru; - if (canThrow(s.aggr, func, mustNotThrow)) - result |= BEthrow; - if (s._body) - result |= blockExit(s._body, func, mustNotThrow) & ~(BEbreak | BEcontinue); - } - - override void visit(ForeachRangeStatement s) - { - assert(global.errors); - result = BEfallthru; - } - - override void visit(IfStatement s) - { - //printf("IfStatement::blockExit(%p)\n", s); - result = BEnone; - if (canThrow(s.condition, func, mustNotThrow)) - result |= BEthrow; - if (s.condition.isBool(true)) - { - result |= blockExit(s.ifbody, func, mustNotThrow); - } - else if (s.condition.isBool(false)) - { - result |= blockExit(s.elsebody, func, mustNotThrow); - } - else - { - result |= blockExit(s.ifbody, func, mustNotThrow); - result |= blockExit(s.elsebody, func, mustNotThrow); - } - //printf("IfStatement::blockExit(%p) = x%x\n", s, result); - } - - override void visit(ConditionalStatement s) - { - result = blockExit(s.ifbody, func, mustNotThrow); - if (s.elsebody) - result |= blockExit(s.elsebody, func, mustNotThrow); - } - - override void visit(PragmaStatement s) - { - result = BEfallthru; - } - - override void visit(StaticAssertStatement s) - { - result = BEfallthru; - } - - override void visit(SwitchStatement s) - { - result = BEnone; - if (canThrow(s.condition, func, mustNotThrow)) - result |= BEthrow; - if (s._body) - { - result |= blockExit(s._body, func, mustNotThrow); - if (result & BEbreak) - { - result |= BEfallthru; - result &= ~BEbreak; - } - } - else - result |= BEfallthru; - } - - override void visit(CaseStatement s) - { - result = blockExit(s.statement, func, mustNotThrow); - } - - override void visit(DefaultStatement s) - { - result = blockExit(s.statement, func, mustNotThrow); - } - - override void visit(GotoDefaultStatement s) - { - result = BEgoto; - } - - override void visit(GotoCaseStatement s) - { - result = BEgoto; - } - - override void visit(SwitchErrorStatement s) - { - // Switch errors are non-recoverable - result = BEhalt; - } - - override void visit(ReturnStatement s) - { - result = BEreturn; - if (s.exp && canThrow(s.exp, func, mustNotThrow)) - result |= BEthrow; - } - - override void visit(BreakStatement s) - { - //printf("BreakStatement::blockExit(%p) = x%x\n", s, s.ident ? BEgoto : BEbreak); - result = s.ident ? BEgoto : BEbreak; - } - - override void visit(ContinueStatement s) - { - result = s.ident ? BEgoto : BEcontinue; - } - - override void visit(SynchronizedStatement s) - { - result = blockExit(s._body, func, mustNotThrow); - } - - override void visit(WithStatement s) - { - result = BEnone; - if (canThrow(s.exp, func, mustNotThrow)) - result = BEthrow; - result |= blockExit(s._body, func, mustNotThrow); - } - - override void visit(TryCatchStatement s) - { - assert(s._body); - result = blockExit(s._body, func, false); - - int catchresult = 0; - foreach (c; *s.catches) - { - if (c.type == Type.terror) - continue; - - int cresult = blockExit(c.handler, func, mustNotThrow); - - /* If we're catching Object, then there is no throwing - */ - Identifier id = c.type.toBasetype().isClassHandle().ident; - if (c.internalCatch && (cresult & BEfallthru)) - { - // https://issues.dlang.org/show_bug.cgi?id=11542 - // leave blockExit flags of the body - cresult &= ~BEfallthru; - } - else if (id == Id.Object || id == Id.Throwable) - { - result &= ~(BEthrow | BEerrthrow); - } - else if (id == Id.Exception) - { - result &= ~BEthrow; - } - catchresult |= cresult; - } - if (mustNotThrow && (result & BEthrow)) - { - // now explain why this is nothrow - blockExit(s._body, func, mustNotThrow); - } - result |= catchresult; - } - - override void visit(TryFinallyStatement s) - { - result = BEfallthru; - if (s._body) - result = blockExit(s._body, func, false); - - // check finally body as well, it may throw (bug #4082) - int finalresult = BEfallthru; - if (s.finalbody) - finalresult = blockExit(s.finalbody, func, false); - - // If either body or finalbody halts - if (result == BEhalt) - finalresult = BEnone; - if (finalresult == BEhalt) - result = BEnone; - - if (mustNotThrow) - { - // now explain why this is nothrow - if (s._body && (result & BEthrow)) - blockExit(s._body, func, mustNotThrow); - if (s.finalbody && (finalresult & BEthrow)) - blockExit(s.finalbody, func, mustNotThrow); - } - - version (none) - { - // https://issues.dlang.org/show_bug.cgi?id=13201 - // Mask to prevent spurious warnings for - // destructor call, exit of synchronized statement, etc. - if (result == BEhalt && finalresult != BEhalt && s.finalbody && s.finalbody.hasCode()) - { - s.finalbody.warning("statement is not reachable"); - } - } - - if (!(finalresult & BEfallthru)) - result &= ~BEfallthru; - result |= finalresult & ~BEfallthru; - } - - override void visit(OnScopeStatement s) - { - // At this point, this statement is just an empty placeholder - result = BEfallthru; - } - - override void visit(ThrowStatement s) - { - if (s.internalThrow) - { - // https://issues.dlang.org/show_bug.cgi?id=8675 - // Allow throwing 'Throwable' object even if mustNotThrow. - result = BEfallthru; - return; - } - - Type t = s.exp.type.toBasetype(); - ClassDeclaration cd = t.isClassHandle(); - assert(cd); - - if (cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null)) - { - result = BEerrthrow; - return; - } - if (mustNotThrow) - s.error("`%s` is thrown but not caught", s.exp.type.toChars()); - - result = BEthrow; - } - - override void visit(GotoStatement s) - { - //printf("GotoStatement::blockExit(%p)\n", s); - result = BEgoto; - } - - override void visit(LabelStatement s) - { - //printf("LabelStatement::blockExit(%p)\n", s); - result = blockExit(s.statement, func, mustNotThrow); - if (s.breaks) - result |= BEfallthru; - } - - override void visit(CompoundAsmStatement s) - { - if (mustNotThrow && !(s.stc & STCnothrow)) - s.deprecation("asm statement is assumed to throw - mark it with `nothrow` if it does not"); - - // Assume the worst - result = BEfallthru | BEreturn | BEgoto | BEhalt; - if (!(s.stc & STCnothrow)) - result |= BEthrow; - } - - override void visit(ImportStatement s) - { - result = BEfallthru; - } - } - - if (!s) - return BEfallthru; - scope BlockExit be = new BlockExit(func, mustNotThrow); - s.accept(be); - return be.result; -} - diff -Nru ldc-1.6.0/ddmd/builtin.d ldc-1.8.0/ddmd/builtin.d --- ldc-1.6.0/ddmd/builtin.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/builtin.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,831 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/builtin.d, _builtin.d) - */ - -module ddmd.builtin; - -// Online documentation: https://dlang.org/phobos/ddmd_builtin.html - -import core.stdc.math; -import core.stdc.string; -import ddmd.arraytypes; -import ddmd.dmangle; -import ddmd.errors; -import ddmd.expression; -import ddmd.func; -import ddmd.globals; -import ddmd.mtype; -import ddmd.root.ctfloat; -import ddmd.root.stringtable; -import ddmd.tokens; -version(IN_LLVM) { - import ddmd.dtemplate; -} - -private: - -/** - * Handler for evaluating builtins during CTFE. - * - * Params: - * loc = The call location, for error reporting. - * fd = The callee declaration, e.g. to disambiguate between different overloads - * in a single handler (LDC). - * arguments = The function call arguments. - * Returns: - * An Expression containing the return value of the call. - */ -extern (C++) alias builtin_fp = Expression function(Loc loc, FuncDeclaration fd, Expressions* arguments); - -__gshared StringTable builtins; - -public extern (C++) void add_builtin(const(char)* mangle, builtin_fp fp) -{ - builtins.insert(mangle, strlen(mangle), cast(void*)fp); -} - -builtin_fp builtin_lookup(const(char)* mangle) -{ - if (const sv = builtins.lookup(mangle, strlen(mangle))) - return cast(builtin_fp)sv.ptrvalue; - return null; -} - -extern (C++) Expression eval_unimp(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - return null; -} - -extern (C++) Expression eval_sin(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.sin(arg0.toReal()), arg0.type); -} - -extern (C++) Expression eval_cos(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.cos(arg0.toReal()), arg0.type); -} - -extern (C++) Expression eval_tan(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.tan(arg0.toReal()), arg0.type); -} - -extern (C++) Expression eval_sqrt(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), arg0.type); -} - -extern (C++) Expression eval_fabs(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.fabs(arg0.toReal()), arg0.type); -} - -extern (C++) Expression eval_ldexp(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - Expression arg1 = (*arguments)[1]; - assert(arg1.op == TOKint64); - return new RealExp(loc, CTFloat.ldexp(arg0.toReal(), cast(int) arg1.toInteger()), arg0.type); -} - -extern (C++) Expression eval_isnan(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new IntegerExp(loc, CTFloat.isNaN(arg0.toReal()), Type.tbool); -} - -extern (C++) Expression eval_isinfinity(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new IntegerExp(loc, CTFloat.isInfinity(arg0.toReal()), Type.tbool); -} - -extern (C++) Expression eval_isfinite(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - const value = !CTFloat.isNaN(arg0.toReal()) && !CTFloat.isInfinity(arg0.toReal()); - return new IntegerExp(loc, value, Type.tbool); -} - -extern (C++) Expression eval_bsf(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKint64); - uinteger_t n = arg0.toInteger(); - if (n == 0) - error(loc, "bsf(0) is undefined"); - n = (n ^ (n - 1)) >> 1; // convert trailing 0s to 1, and zero rest - int k = 0; - while (n) - { - ++k; - n >>= 1; - } - return new IntegerExp(loc, k, Type.tint32); -} - -extern (C++) Expression eval_bsr(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKint64); - uinteger_t n = arg0.toInteger(); - if (n == 0) - error(loc, "bsr(0) is undefined"); - int k = 0; - while (n >>= 1) - { - ++k; - } - return new IntegerExp(loc, k, Type.tint32); -} - -version(IN_LLVM) -{ - -private Type getTypeOfOverloadedIntrinsic(FuncDeclaration fd) -{ - // Depending on the state of the code generation we have to look at - // the template instance or the function declaration. - assert(fd.parent && "function declaration requires parent"); - TemplateInstance tinst = fd.parent.isTemplateInstance(); - if (tinst) - { - // See DtoOverloadedIntrinsicName - assert(tinst.tdtypes.dim == 1); - return cast(Type) tinst.tdtypes.data[0]; - } - else - { - assert(fd.type.ty == Tfunction); - TypeFunction tf = cast(TypeFunction) fd.type; - assert(tf.parameters.dim >= 1); - return tf.parameters.data[0].type; - } -} - -private int getBitsizeOfType(Loc loc, Type type) -{ - switch (type.toBasetype().ty) - { - case Tint64: - case Tuns64: return 64; - case Tint32: - case Tuns32: return 32; - case Tint16: - case Tuns16: return 16; - case Tint128: - case Tuns128: - error(loc, "cent/ucent not supported"); - break; - default: - error(loc, "unsupported type"); - break; - } - return 32; // in case of error -} - -extern (C++) Expression eval_llvmsin(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.sin(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmcos(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.cos(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmsqrt(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.sqrt(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmlog(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.log(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmlog2(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.log2(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmlog10(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.log10(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmfabs(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.fabs(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmminnum(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - Expression arg1 = (*arguments)[1]; - assert(arg1.op == TOKfloat64); - return new RealExp(loc, CTFloat.fmin(arg0.toReal(), arg1.toReal()), type); -} - -extern (C++) Expression eval_llvmmaxnum(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - Expression arg1 = (*arguments)[1]; - assert(arg1.op == TOKfloat64); - return new RealExp(loc, CTFloat.fmax(arg0.toReal(), arg1.toReal()), type); -} - -extern (C++) Expression eval_llvmfloor(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.floor(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmceil(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.ceil(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmtrunc(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.trunc(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmrint(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.rint(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmnearbyint(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.nearbyint(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmround(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - return new RealExp(loc, CTFloat.round(arg0.toReal()), type); -} - -extern (C++) Expression eval_llvmfma(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - Expression arg1 = (*arguments)[1]; - assert(arg1.op == TOKfloat64); - Expression arg2 = (*arguments)[2]; - assert(arg2.op == TOKfloat64); - return new RealExp(loc, CTFloat.fma(arg0.toReal(), arg1.toReal(), arg2.toReal()), type); -} - -extern (C++) Expression eval_llvmcopysign(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - Expression arg1 = (*arguments)[1]; - assert(arg1.op == TOKfloat64); - return new RealExp(loc, CTFloat.copysign(arg0.toReal(), arg1.toReal()), type); -} - -extern (C++) Expression eval_cttz(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKint64); - uinteger_t x = arg0.toInteger(); - - int n = getBitsizeOfType(loc, type); - - if (x == 0) - { - if ((*arguments)[1].toInteger()) - error(loc, "llvm.cttz.i#(0) is undefined"); - } - else - { - int c = n >> 1; - n -= 1; - const uinteger_t mask = (uinteger_t(1L) << n) | (uinteger_t(1L) << n)-1; - do { - uinteger_t y = (x << c) & mask; - if (y != 0) { n -= c; x = y; } - c = c >> 1; - } while (c != 0); - } - - return new IntegerExp(loc, n, type); -} - -extern (C++) Expression eval_ctlz(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKint64); - uinteger_t x = arg0.toInteger(); - if (x == 0 && (*arguments)[1].toInteger()) - error(loc, "llvm.ctlz.i#(0) is undefined"); - - int n = getBitsizeOfType(loc, type); - int c = n >> 1; - do { - uinteger_t y = x >> c; if (y != 0) { n -= c; x = y; } - c = c >> 1; - } while (c != 0); - - return new IntegerExp(loc, n - x, type); -} - -extern (C++) Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - Type type = getTypeOfOverloadedIntrinsic(fd); - - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKint64); - uinteger_t n = arg0.toInteger(); - enum ulong BYTEMASK = 0x00FF00FF00FF00FF; - enum ulong SHORTMASK = 0x0000FFFF0000FFFF; - enum ulong INTMASK = 0x00000000FFFFFFFF; - switch (type.toBasetype().ty) - { - case Tint64: - case Tuns64: - // swap high and low uints - n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32); - goto case Tuns32; - case Tint32: - case Tuns32: - // swap adjacent ushorts - n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16); - goto case Tuns16; - case Tint16: - case Tuns16: - // swap adjacent ubytes - n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 ); - break; - case Tint128: - case Tuns128: - error(loc, "cent/ucent not supported"); - break; - default: - error(loc, "unsupported type"); - break; - } - return new IntegerExp(loc, n, type); -} - -extern (C++) Expression eval_ctpop(Loc loc, FuncDeclaration fd, Expressions *arguments) -{ - // FIXME Does not work for cent/ucent - Type type = getTypeOfOverloadedIntrinsic(fd); - - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKint64); - uinteger_t n = arg0.toInteger(); - int cnt = 0; - while (n) - { - cnt += (n & 1); - n >>= 1; - } - return new IntegerExp(loc, cnt, type); -} - -} -else // !IN_LLVM -{ - -extern (C++) Expression eval_bswap(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKint64); - uinteger_t n = arg0.toInteger(); - enum BYTEMASK = 0x00FF00FF00FF00FFL; - enum SHORTMASK = 0x0000FFFF0000FFFFL; - enum INTMASK = 0x0000FFFF0000FFFFL; - // swap adjacent ubytes - n = ((n >> 8) & BYTEMASK) | ((n & BYTEMASK) << 8); - // swap adjacent ushorts - n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16); - TY ty = arg0.type.toBasetype().ty; - // If 64 bits, we need to swap high and low uints - if (ty == Tint64 || ty == Tuns64) - n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32); - return new IntegerExp(loc, n, arg0.type); -} - -} // !IN_LLVM - -extern (C++) Expression eval_popcnt(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKint64); - uinteger_t n = arg0.toInteger(); - int cnt = 0; - while (n) - { - cnt += (n & 1); - n >>= 1; - } - return new IntegerExp(loc, cnt, arg0.type); -} - -extern (C++) Expression eval_yl2x(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - Expression arg1 = (*arguments)[1]; - assert(arg1.op == TOKfloat64); - const x = arg0.toReal(); - const y = arg1.toReal(); - real_t result = 0; - CTFloat.yl2x(&x, &y, &result); - return new RealExp(loc, result, arg0.type); -} - -extern (C++) Expression eval_yl2xp1(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - Expression arg0 = (*arguments)[0]; - assert(arg0.op == TOKfloat64); - Expression arg1 = (*arguments)[1]; - assert(arg1.op == TOKfloat64); - const x = arg0.toReal(); - const y = arg1.toReal(); - real_t result = 0; - CTFloat.yl2xp1(&x, &y, &result); - return new RealExp(loc, result, arg0.type); -} - -public extern (C++) void builtin_init() -{ -version(IN_LLVM) -{ - builtins._init(127); // Prime number like default value -} -else -{ - builtins._init(47); -} - // @safe @nogc pure nothrow real function(real) - add_builtin("_D4core4math3sinFNaNbNiNfeZe", &eval_sin); - add_builtin("_D4core4math3cosFNaNbNiNfeZe", &eval_cos); - add_builtin("_D4core4math3tanFNaNbNiNfeZe", &eval_tan); - add_builtin("_D4core4math4sqrtFNaNbNiNfeZe", &eval_sqrt); - add_builtin("_D4core4math4fabsFNaNbNiNfeZe", &eval_fabs); - add_builtin("_D4core4math5expm1FNaNbNiNfeZe", &eval_unimp); - add_builtin("_D4core4math4exp21FNaNbNiNfeZe", &eval_unimp); - // @trusted @nogc pure nothrow real function(real) - add_builtin("_D4core4math3sinFNaNbNiNeeZe", &eval_sin); - add_builtin("_D4core4math3cosFNaNbNiNeeZe", &eval_cos); - add_builtin("_D4core4math3tanFNaNbNiNeeZe", &eval_tan); - add_builtin("_D4core4math4sqrtFNaNbNiNeeZe", &eval_sqrt); - add_builtin("_D4core4math4fabsFNaNbNiNeeZe", &eval_fabs); - add_builtin("_D4core4math5expm1FNaNbNiNeeZe", &eval_unimp); - add_builtin("_D4core4math4exp21FNaNbNiNeeZe", &eval_unimp); - // @safe @nogc pure nothrow double function(double) - add_builtin("_D4core4math4sqrtFNaNbNiNfdZd", &eval_sqrt); - // @safe @nogc pure nothrow float function(float) - add_builtin("_D4core4math4sqrtFNaNbNiNffZf", &eval_sqrt); - // @safe @nogc pure nothrow real function(real, real) - add_builtin("_D4core4math5atan2FNaNbNiNfeeZe", &eval_unimp); - if (CTFloat.yl2x_supported) - { - version(IN_LLVM) // @trusted - add_builtin("_D4core4math4yl2xFNaNbNiNeeeZe", &eval_yl2x); - else - add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); - } - else - { - add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_unimp); - } - if (CTFloat.yl2xp1_supported) - { - version(IN_LLVM) // @trusted - add_builtin("_D4core4math6yl2xp1FNaNbNiNeeeZe", &eval_yl2xp1); - else - add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); - } - else - { - add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); - } - // @safe @nogc pure nothrow long function(real) - add_builtin("_D4core4math6rndtolFNaNbNiNfeZl", &eval_unimp); - // @safe @nogc pure nothrow real function(real) - add_builtin("_D3std4math3sinFNaNbNiNfeZe", &eval_sin); - add_builtin("_D3std4math3cosFNaNbNiNfeZe", &eval_cos); - add_builtin("_D3std4math3tanFNaNbNiNfeZe", &eval_tan); - add_builtin("_D3std4math4sqrtFNaNbNiNfeZe", &eval_sqrt); - add_builtin("_D3std4math4fabsFNaNbNiNfeZe", &eval_fabs); - add_builtin("_D3std4math5expm1FNaNbNiNfeZe", &eval_unimp); - add_builtin("_D3std4math4exp21FNaNbNiNfeZe", &eval_unimp); - // @trusted @nogc pure nothrow real function(real) - add_builtin("_D3std4math3sinFNaNbNiNeeZe", &eval_sin); - add_builtin("_D3std4math3cosFNaNbNiNeeZe", &eval_cos); - add_builtin("_D3std4math3tanFNaNbNiNeeZe", &eval_tan); - add_builtin("_D3std4math4sqrtFNaNbNiNeeZe", &eval_sqrt); - add_builtin("_D3std4math4fabsFNaNbNiNeeZe", &eval_fabs); - add_builtin("_D3std4math5expm1FNaNbNiNeeZe", &eval_unimp); - add_builtin("_D3std4math4exp21FNaNbNiNeeZe", &eval_unimp); - // @safe @nogc pure nothrow double function(double) - add_builtin("_D3std4math4sqrtFNaNbNiNfdZd", &eval_sqrt); - // @safe @nogc pure nothrow float function(float) - add_builtin("_D3std4math4sqrtFNaNbNiNffZf", &eval_sqrt); - // @safe @nogc pure nothrow real function(real, real) - add_builtin("_D3std4math5atan2FNaNbNiNfeeZe", &eval_unimp); - if (CTFloat.yl2x_supported) - { - add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); - } - else - { - add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_unimp); - } - if (CTFloat.yl2xp1_supported) - { - add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); - } - else - { - add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); - } - // @safe @nogc pure nothrow long function(real) - add_builtin("_D3std4math6rndtolFNaNbNiNfeZl", &eval_unimp); - - // @safe @nogc pure nothrow T function(T, int) - add_builtin("_D4core4math5ldexpFNaNbNiNfeiZe", &eval_ldexp); - add_builtin("_D3std4math5ldexpFNaNbNiNfeiZe", &eval_ldexp); - add_builtin("_D3std4math5ldexpFNaNbNiNfdiZd", &eval_ldexp); - add_builtin("_D3std4math5ldexpFNaNbNiNffiZf", &eval_ldexp); - - // @trusted @nogc pure nothrow bool function(T) - add_builtin("_D3std4math12__T5isNaNTeZ5isNaNFNaNbNiNeeZb", &eval_isnan); - add_builtin("_D3std4math12__T5isNaNTdZ5isNaNFNaNbNiNedZb", &eval_isnan); - add_builtin("_D3std4math12__T5isNaNTfZ5isNaNFNaNbNiNefZb", &eval_isnan); - add_builtin("_D3std4math18__T10isInfinityTeZ10isInfinityFNaNbNiNeeZb", &eval_isinfinity); - add_builtin("_D3std4math18__T10isInfinityTdZ10isInfinityFNaNbNiNedZb", &eval_isinfinity); - add_builtin("_D3std4math18__T10isInfinityTfZ10isInfinityFNaNbNiNefZb", &eval_isinfinity); - add_builtin("_D3std4math15__T8isFiniteTeZ8isFiniteFNaNbNiNeeZb", &eval_isfinite); - add_builtin("_D3std4math15__T8isFiniteTdZ8isFiniteFNaNbNiNedZb", &eval_isfinite); - add_builtin("_D3std4math15__T8isFiniteTfZ8isFiniteFNaNbNiNefZb", &eval_isfinite); - -version(IN_LLVM) -{ - // intrinsic llvm.sin.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.sin.f32", &eval_llvmsin); - add_builtin("llvm.sin.f64", &eval_llvmsin); - add_builtin("llvm.sin.f80", &eval_llvmsin); - add_builtin("llvm.sin.f128", &eval_llvmsin); - add_builtin("llvm.sin.ppcf128", &eval_llvmsin); - - // intrinsic llvm.cos.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.cos.f32", &eval_llvmcos); - add_builtin("llvm.cos.f64", &eval_llvmcos); - add_builtin("llvm.cos.f80", &eval_llvmcos); - add_builtin("llvm.cos.f128", &eval_llvmcos); - add_builtin("llvm.cos.ppcf128", &eval_llvmcos); - - // intrinsic llvm.sqrt.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.sqrt.f32", &eval_llvmsqrt); - add_builtin("llvm.sqrt.f64", &eval_llvmsqrt); - add_builtin("llvm.sqrt.f80", &eval_llvmsqrt); - add_builtin("llvm.sqrt.f128", &eval_llvmsqrt); - add_builtin("llvm.sqrt.ppcf128", &eval_llvmsqrt); - - // intrinsic llvm.log.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.log.f32", &eval_llvmlog); - add_builtin("llvm.log.f64", &eval_llvmlog); - add_builtin("llvm.log.f80", &eval_llvmlog); - add_builtin("llvm.log.f128", &eval_llvmlog); - add_builtin("llvm.log.ppcf128", &eval_llvmlog); - - // intrinsic llvm.log2.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.log2.f32", &eval_llvmlog2); - add_builtin("llvm.log2.f64", &eval_llvmlog2); - add_builtin("llvm.log2.f80", &eval_llvmlog2); - add_builtin("llvm.log2.f128", &eval_llvmlog2); - add_builtin("llvm.log2.ppcf128", &eval_llvmlog2); - - // intrinsic llvm.log10.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.log10.f32", &eval_llvmlog10); - add_builtin("llvm.log10.f64", &eval_llvmlog10); - add_builtin("llvm.log10.f80", &eval_llvmlog10); - add_builtin("llvm.log10.f128", &eval_llvmlog10); - add_builtin("llvm.log10.ppcf128", &eval_llvmlog10); - - // intrinsic llvm.fabs.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.fabs.f32", &eval_llvmfabs); - add_builtin("llvm.fabs.f64", &eval_llvmfabs); - add_builtin("llvm.fabs.f80", &eval_llvmfabs); - add_builtin("llvm.fabs.f128", &eval_llvmfabs); - add_builtin("llvm.fabs.ppcf128", &eval_llvmfabs); - - // intrinsic llvm.minnum.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.minnum.f32", &eval_llvmminnum); - add_builtin("llvm.minnum.f64", &eval_llvmminnum); - add_builtin("llvm.minnum.f80", &eval_llvmminnum); - add_builtin("llvm.minnum.f128", &eval_llvmminnum); - add_builtin("llvm.minnum.ppcf128", &eval_llvmminnum); - - // intrinsic llvm.maxnum.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.maxnum.f32", &eval_llvmmaxnum); - add_builtin("llvm.maxnum.f64", &eval_llvmmaxnum); - add_builtin("llvm.maxnum.f80", &eval_llvmmaxnum); - add_builtin("llvm.maxnum.f128", &eval_llvmmaxnum); - add_builtin("llvm.maxnum.ppcf128", &eval_llvmmaxnum); - - // intrinsic llvm.floor.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.floor.f32", &eval_llvmfloor); - add_builtin("llvm.floor.f64", &eval_llvmfloor); - add_builtin("llvm.floor.f80", &eval_llvmfloor); - add_builtin("llvm.floor.f128", &eval_llvmfloor); - add_builtin("llvm.floor.ppcf128", &eval_llvmfloor); - - // intrinsic llvm.ceil.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.ceil.f32", &eval_llvmceil); - add_builtin("llvm.ceil.f64", &eval_llvmceil); - add_builtin("llvm.ceil.f80", &eval_llvmceil); - add_builtin("llvm.ceil.f128", &eval_llvmceil); - add_builtin("llvm.ceil.ppcf128", &eval_llvmceil); - - // intrinsic llvm.trunc.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.trunc.f32", &eval_llvmtrunc); - add_builtin("llvm.trunc.f64", &eval_llvmtrunc); - add_builtin("llvm.trunc.f80", &eval_llvmtrunc); - add_builtin("llvm.trunc.f128", &eval_llvmtrunc); - add_builtin("llvm.trunc.ppcf128", &eval_llvmtrunc); - - // intrinsic llvm.rint.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.rint.f32", &eval_llvmrint); - add_builtin("llvm.rint.f64", &eval_llvmrint); - add_builtin("llvm.rint.f80", &eval_llvmrint); - add_builtin("llvm.rint.f128", &eval_llvmrint); - add_builtin("llvm.rint.ppcf128", &eval_llvmrint); - - // intrinsic llvm.nearbyint.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.nearbyint.f32", &eval_llvmnearbyint); - add_builtin("llvm.nearbyint.f64", &eval_llvmnearbyint); - add_builtin("llvm.nearbyint.f80", &eval_llvmnearbyint); - add_builtin("llvm.nearbyint.f128", &eval_llvmnearbyint); - add_builtin("llvm.nearbyint.ppcf128", &eval_llvmnearbyint); - - // intrinsic llvm.round.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.round.f32", &eval_llvmround); - add_builtin("llvm.round.f64", &eval_llvmround); - add_builtin("llvm.round.f80", &eval_llvmround); - add_builtin("llvm.round.f128", &eval_llvmround); - add_builtin("llvm.round.ppcf128", &eval_llvmround); - - // intrinsic llvm.fma.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.fma.f32", &eval_llvmfma); - add_builtin("llvm.fma.f64", &eval_llvmfma); - add_builtin("llvm.fma.f80", &eval_llvmfma); - add_builtin("llvm.fma.f128", &eval_llvmfma); - add_builtin("llvm.fma.ppcf128", &eval_llvmfma); - - // intrinsic llvm.copysign.f32/f64/f80/f128/ppcf128 - add_builtin("llvm.copysign.f32", &eval_llvmcopysign); - add_builtin("llvm.copysign.f64", &eval_llvmcopysign); - add_builtin("llvm.copysign.f80", &eval_llvmcopysign); - add_builtin("llvm.copysign.f128", &eval_llvmcopysign); - add_builtin("llvm.copysign.ppcf128", &eval_llvmcopysign); - - // intrinsic llvm.bswap.i16/i32/i64/i128 - add_builtin("llvm.bswap.i16", &eval_bswap); - add_builtin("llvm.bswap.i32", &eval_bswap); - add_builtin("llvm.bswap.i64", &eval_bswap); - add_builtin("llvm.bswap.i128", &eval_bswap); - - // intrinsic llvm.cttz.i8/i16/i32/i64/i128 - add_builtin("llvm.cttz.i8", &eval_cttz); - add_builtin("llvm.cttz.i16", &eval_cttz); - add_builtin("llvm.cttz.i32", &eval_cttz); - add_builtin("llvm.cttz.i64", &eval_cttz); - add_builtin("llvm.cttz.i128", &eval_cttz); - - // intrinsic llvm.ctlz.i8/i16/i32/i64/i128 - add_builtin("llvm.ctlz.i8", &eval_ctlz); - add_builtin("llvm.ctlz.i16", &eval_ctlz); - add_builtin("llvm.ctlz.i32", &eval_ctlz); - add_builtin("llvm.ctlz.i64", &eval_ctlz); - add_builtin("llvm.ctlz.i128", &eval_ctlz); - - // intrinsic llvm.ctpop.i8/i16/i32/i64/i128 - add_builtin("llvm.ctpop.i8", &eval_ctpop); - add_builtin("llvm.ctpop.i16", &eval_ctpop); - add_builtin("llvm.ctpop.i32", &eval_ctpop); - add_builtin("llvm.ctpop.i64", &eval_ctpop); - add_builtin("llvm.ctpop.i128", &eval_ctpop); -} - - // @safe @nogc pure nothrow int function(uint) - add_builtin("_D4core5bitop3bsfFNaNbNiNfkZi", &eval_bsf); - add_builtin("_D4core5bitop3bsrFNaNbNiNfkZi", &eval_bsr); - // @safe @nogc pure nothrow int function(ulong) - add_builtin("_D4core5bitop3bsfFNaNbNiNfmZi", &eval_bsf); - add_builtin("_D4core5bitop3bsrFNaNbNiNfmZi", &eval_bsr); - // @safe @nogc pure nothrow uint function(uint) - add_builtin("_D4core5bitop5bswapFNaNbNiNfkZk", &eval_bswap); - // @safe @nogc pure nothrow int function(uint) - add_builtin("_D4core5bitop7_popcntFNaNbNiNfkZi", &eval_popcnt); - // @safe @nogc pure nothrow ushort function(ushort) - add_builtin("_D4core5bitop7_popcntFNaNbNiNftZt", &eval_popcnt); - // @safe @nogc pure nothrow int function(ulong) - if (global.params.is64bit) - add_builtin("_D4core5bitop7_popcntFNaNbNiNfmZi", &eval_popcnt); -} - -/********************************** - * Determine if function is a builtin one that we can - * evaluate at compile time. - */ -public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd) -{ - if (fd.builtin == BUILTINunknown) - { - builtin_fp fp = builtin_lookup(mangleExact(fd)); - fd.builtin = fp ? BUILTINyes : BUILTINno; - } - return fd.builtin; -} - -/************************************** - * Evaluate builtin function. - * Return result; NULL if cannot evaluate it. - */ -public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments) -{ - if (fd.builtin == BUILTINyes) - { - builtin_fp fp = builtin_lookup(mangleExact(fd)); - assert(fp); - return fp(loc, fd, arguments); - } - return null; -} diff -Nru ldc-1.6.0/ddmd/canthrow.d ldc-1.8.0/ddmd/canthrow.d --- ldc-1.6.0/ddmd/canthrow.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/canthrow.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,312 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/canthrow.d, _canthrow.d) - */ - -module ddmd.canthrow; - -// Online documentation: https://dlang.org/phobos/ddmd_canthrow.html - -import ddmd.aggregate; -import ddmd.apply; -import ddmd.arraytypes; -import ddmd.attrib; -import ddmd.declaration; -import ddmd.dstruct; -import ddmd.dsymbol; -import ddmd.dtemplate; -import ddmd.expression; -import ddmd.func; -import ddmd.globals; -import ddmd.init; -import ddmd.mtype; -import ddmd.root.rootobject; -import ddmd.tokens; -import ddmd.visitor; - -/******************************************** - * Returns true if the expression may throw exceptions. - * If 'mustNotThrow' is true, generate an error if it throws - */ -extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow) -{ - //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars()); - // stop walking if we determine this expression can throw - extern (C++) final class CanThrow : StoppableVisitor - { - alias visit = super.visit; - FuncDeclaration func; - bool mustNotThrow; - - public: - extern (D) this(FuncDeclaration func, bool mustNotThrow) - { - this.func = func; - this.mustNotThrow = mustNotThrow; - } - - override void visit(Expression) - { - } - - override void visit(DeclarationExp de) - { - stop = Dsymbol_canThrow(de.declaration, func, mustNotThrow); - } - - override void visit(CallExp ce) - { - if (global.errors && !ce.e1.type) - return; // error recovery - /* If calling a function or delegate that is typed as nothrow, - * then this expression cannot throw. - * Note that pure functions can throw. - */ - Type t = ce.e1.type.toBasetype(); - if (ce.f && ce.f == func) - return; - if (t.ty == Tfunction && (cast(TypeFunction)t).isnothrow) - return; - if (t.ty == Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) - return; - - if (mustNotThrow) - { - if (ce.f) - { - ce.error("%s `%s` is not nothrow", - ce.f.kind(), ce.f.toPrettyChars()); - } - else - { - auto e1 = ce.e1; - if (e1.op == TOKstar) // print 'fp' if e1 is (*fp) - e1 = (cast(PtrExp)e1).e1; - ce.error("`%s` is not nothrow", e1.toChars()); - } - } - stop = true; - } - - override void visit(NewExp ne) - { - if (ne.member) - { - if (ne.allocator) - { - // https://issues.dlang.org/show_bug.cgi?id=14407 - Type t = ne.allocator.type.toBasetype(); - if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) - { - if (mustNotThrow) - { - ne.error("%s `%s` is not nothrow", - ne.allocator.kind(), ne.allocator.toPrettyChars()); - } - stop = true; - } - } - // See if constructor call can throw - Type t = ne.member.type.toBasetype(); - if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) - { - if (mustNotThrow) - { - ne.error("%s `%s` is not nothrow", - ne.member.kind(), ne.member.toPrettyChars()); - } - stop = true; - } - } - // regard storage allocation failures as not recoverable - } - - override void visit(DeleteExp de) - { - Type tb = de.e1.type.toBasetype(); - AggregateDeclaration ad = null; - switch (tb.ty) - { - case Tclass: - ad = (cast(TypeClass)tb).sym; - break; - - case Tpointer: - tb = (cast(TypePointer)tb).next.toBasetype(); - if (tb.ty == Tstruct) - ad = (cast(TypeStruct)tb).sym; - break; - - case Tarray: - Type tv = tb.nextOf().baseElemOf(); - if (tv.ty == Tstruct) - ad = (cast(TypeStruct)tv).sym; - break; - - default: - break; - } - if (!ad) - return; - - if (ad.dtor) - { - Type t = ad.dtor.type.toBasetype(); - if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) - { - if (mustNotThrow) - { - de.error("%s `%s` is not nothrow", - ad.dtor.kind(), ad.dtor.toPrettyChars()); - } - stop = true; - } - } - if (ad.aggDelete && tb.ty != Tarray) - { - Type t = ad.aggDelete.type; - if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) - { - if (mustNotThrow) - { - de.error("%s `%s` is not nothrow", - ad.aggDelete.kind(), ad.aggDelete.toPrettyChars()); - } - stop = true; - } - } - } - - override void visit(AssignExp ae) - { - // blit-init cannot throw - if (ae.op == TOKblit) - return; - /* Element-wise assignment could invoke postblits. - */ - Type t; - if (ae.type.toBasetype().ty == Tsarray) - { - if (!ae.e2.isLvalue()) - return; - t = ae.type; - } - else if (ae.e1.op == TOKslice) - t = (cast(SliceExp)ae.e1).e1.type; - else - return; - Type tv = t.baseElemOf(); - if (tv.ty != Tstruct) - return; - StructDeclaration sd = (cast(TypeStruct)tv).sym; - if (!sd.postblit || sd.postblit.type.ty != Tfunction) - return; - if ((cast(TypeFunction)sd.postblit.type).isnothrow) - { - } - else - { - if (mustNotThrow) - { - ae.error("%s `%s` is not nothrow", - sd.postblit.kind(), sd.postblit.toPrettyChars()); - } - stop = true; - } - } - - override void visit(NewAnonClassExp) - { - assert(0); // should have been lowered by semantic() - } - } - - scope CanThrow ct = new CanThrow(func, mustNotThrow); - return walkPostorder(e, ct); -} - -/************************************** - * Does symbol, when initialized, throw? - * Mirrors logic in Dsymbol_toElem(). - */ -extern (C++) bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow) -{ - AttribDeclaration ad; - VarDeclaration vd; - TemplateMixin tm; - TupleDeclaration td; - //printf("Dsymbol_toElem() %s\n", s.toChars()); - ad = s.isAttribDeclaration(); - if (ad) - { - Dsymbols* decl = ad.include(null, null); - if (decl && decl.dim) - { - for (size_t i = 0; i < decl.dim; i++) - { - s = (*decl)[i]; - if (Dsymbol_canThrow(s, func, mustNotThrow)) - return true; - } - } - } - else if ((vd = s.isVarDeclaration()) !is null) - { - s = s.toAlias(); - if (s != vd) - return Dsymbol_canThrow(s, func, mustNotThrow); - if (vd.storage_class & STCmanifest) - { - } - else if (vd.isStatic() || vd.storage_class & (STCextern | STCtls | STCgshared)) - { - } - else - { - if (vd._init) - { - ExpInitializer ie = vd._init.isExpInitializer(); - if (ie && canThrow(ie.exp, func, mustNotThrow)) - return true; - } - if (vd.needsScopeDtor()) - return canThrow(vd.edtor, func, mustNotThrow); - } - } - else if ((tm = s.isTemplateMixin()) !is null) - { - //printf("%s\n", tm.toChars()); - if (tm.members) - { - for (size_t i = 0; i < tm.members.dim; i++) - { - Dsymbol sm = (*tm.members)[i]; - if (Dsymbol_canThrow(sm, func, mustNotThrow)) - return true; - } - } - } - else if ((td = s.isTupleDeclaration()) !is null) - { - for (size_t i = 0; i < td.objects.dim; i++) - { - RootObject o = (*td.objects)[i]; - if (o.dyncast() == DYNCAST.expression) - { - Expression eo = cast(Expression)o; - if (eo.op == TOKdsymbol) - { - DsymbolExp se = cast(DsymbolExp)eo; - if (Dsymbol_canThrow(se.s, func, mustNotThrow)) - return true; - } - } - } - } - return false; -} diff -Nru ldc-1.6.0/ddmd/clone.d ldc-1.8.0/ddmd/clone.d --- ldc-1.6.0/ddmd/clone.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/clone.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,1187 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/clone.d, _clone.d) - */ - -module ddmd.clone; - -// Online documentation: https://dlang.org/phobos/ddmd_clone.html - -import core.stdc.stdio; -import ddmd.aggregate; -import ddmd.arraytypes; -import ddmd.declaration; -import ddmd.dscope; -import ddmd.dstruct; -import ddmd.dsymbol; -import ddmd.dtemplate; -import ddmd.expression; -import ddmd.expressionsem; -import ddmd.func; -import ddmd.globals; -import ddmd.id; -import ddmd.identifier; -import ddmd.init; -import ddmd.mtype; -import ddmd.opover; -import ddmd.statement; -import ddmd.tokens; - -/******************************************* - * Merge function attributes pure, nothrow, @safe, @nogc, and @disable - */ -extern (C++) StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration f) -{ - if (!f) - return s1; - StorageClass s2 = (f.storage_class & STCdisable); - TypeFunction tf = cast(TypeFunction)f.type; - if (tf.trust == TRUSTsafe) - s2 |= STCsafe; - else if (tf.trust == TRUSTsystem) - s2 |= STCsystem; - else if (tf.trust == TRUSTtrusted) - s2 |= STCtrusted; - if (tf.purity != PUREimpure) - s2 |= STCpure; - if (tf.isnothrow) - s2 |= STCnothrow; - if (tf.isnogc) - s2 |= STCnogc; - StorageClass stc = 0; - StorageClass sa = s1 & s2; - StorageClass so = s1 | s2; - if (so & STCsystem) - stc |= STCsystem; - else if (sa & STCtrusted) - stc |= STCtrusted; - else if ((so & (STCtrusted | STCsafe)) == (STCtrusted | STCsafe)) - stc |= STCtrusted; - else if (sa & STCsafe) - stc |= STCsafe; - if (sa & STCpure) - stc |= STCpure; - if (sa & STCnothrow) - stc |= STCnothrow; - if (sa & STCnogc) - stc |= STCnogc; - if (so & STCdisable) - stc |= STCdisable; - return stc; -} - -/******************************************* - * Check given aggregate actually has an identity opAssign or not. - * Params: - * ad = struct or class - * sc = current scope - * Returns: - * if found, returns FuncDeclaration of opAssign, otherwise null - */ -extern (C++) FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc) -{ - Dsymbol assign = search_function(ad, Id.assign); - if (assign) - { - /* check identity opAssign exists - */ - scope er = new NullExp(ad.loc, ad.type); // dummy rvalue - scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue - el.type = ad.type; - Expressions a; - a.setDim(1); - const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. - sc = sc.push(); - sc.tinst = null; - sc.minst = null; - - a[0] = er; - auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, 1); - if (!f) - { - a[0] = el; - f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, 1); - } - - sc = sc.pop(); - global.endGagging(errors); - if (f) - { - if (f.errors) - return null; - int varargs; - auto fparams = f.getParameters(&varargs); - if (fparams.dim >= 1) - { - auto fparam0 = Parameter.getNth(fparams, 0); - if (fparam0.type.toDsymbol(null) != ad) - f = null; - } - } - // BUGS: This detection mechanism cannot find some opAssign-s like follows: - // struct S { void opAssign(ref immutable S) const; } - return f; - } - return null; -} - -/******************************************* - * We need an opAssign for the struct if - * it has a destructor or a postblit. - * We need to generate one if a user-specified one does not exist. - */ -private bool needOpAssign(StructDeclaration sd) -{ - //printf("StructDeclaration::needOpAssign() %s\n", sd.toChars()); - if (sd.isUnionDeclaration()) - return false; - - if (sd.hasIdentityAssign) - goto Lneed; // because has identity==elaborate opAssign - - if (sd.dtor || sd.postblit) - goto Lneed; - /* If any of the fields need an opAssign, then we - * need it too. - */ - for (size_t i = 0; i < sd.fields.dim; i++) - { - VarDeclaration v = sd.fields[i]; - if (v.storage_class & STCref) - continue; - if (v.overlapped) // if field of a union - continue; // user must handle it themselves - Type tv = v.type.baseElemOf(); - if (tv.ty == Tstruct) - { - TypeStruct ts = cast(TypeStruct)tv; - if (ts.sym.isUnionDeclaration()) - continue; - if (needOpAssign(ts.sym)) - goto Lneed; - } - } - //printf("\tdontneed\n"); - return false; -Lneed: - //printf("\tneed\n"); - return true; -} - -/****************************************** - * Build opAssign for struct. - * ref S opAssign(S s) { ... } - * - * Note that s will be constructed onto the stack, and probably - * copy-constructed in caller site. - * - * If S has copy copy construction and/or destructor, - * the body will make bit-wise object swap: - * S __swap = this; // bit copy - * this = s; // bit copy - * __swap.dtor(); - * Instead of running the destructor on s, run it on tmp instead. - * - * Otherwise, the body will make member-wise assignments: - * Then, the body is: - * this.field1 = s.field1; - * this.field2 = s.field2; - * ...; - */ -extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) -{ - if (FuncDeclaration f = hasIdentityOpAssign(sd, sc)) - { - sd.hasIdentityAssign = true; - return f; - } - // Even if non-identity opAssign is defined, built-in identity opAssign - // will be defined. - if (!needOpAssign(sd)) - return null; - - //printf("StructDeclaration::buildOpAssign() %s\n", sd.toChars()); - StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; - Loc declLoc = sd.loc; - Loc loc = Loc(); // internal code should have no loc to prevent coverage - - // One of our sub-field might have `@disable opAssign` so we need to - // check for it. - // In this event, it will be reflected by having `stc` (opAssign's - // storage class) include `STCdisabled`. - for (size_t i = 0; i < sd.fields.dim; i++) - { - VarDeclaration v = sd.fields[i]; - if (v.storage_class & STCref) - continue; - if (v.overlapped) - continue; - Type tv = v.type.baseElemOf(); - if (tv.ty != Tstruct) - continue; - StructDeclaration sdv = (cast(TypeStruct)tv).sym; - stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc)); - } - - if (sd.dtor || sd.postblit) - { - if (!sd.type.isAssignable()) // https://issues.dlang.org/show_bug.cgi?id=13044 - return null; - stc = mergeFuncAttrs(stc, sd.dtor); - if (stc & STCsafe) - stc = (stc & ~STCsafe) | STCtrusted; - } - - auto fparams = new Parameters(); - fparams.push(new Parameter(STCnodtor, sd.type, Id.p, null)); - auto tf = new TypeFunction(fparams, sd.handleType(), 0, LINKd, stc | STCref); - auto fop = new FuncDeclaration(declLoc, Loc(), Id.assign, stc, tf); - fop.storage_class |= STCinference; - fop.generated = true; - Expression e = null; - if (stc & STCdisable) - { - } - else if (sd.dtor || sd.postblit) - { - /* Do swap this and rhs. - * __swap = this; this = s; __swap.dtor(); - */ - //printf("\tswap copy\n"); - Identifier idtmp = Identifier.generateId("__swap"); - VarDeclaration tmp = null; - AssignExp ec = null; - if (sd.dtor) - { - tmp = new VarDeclaration(loc, sd.type, idtmp, new VoidInitializer(loc)); - tmp.storage_class |= STCnodtor | STCtemp | STCctfe; - e = new DeclarationExp(loc, tmp); - ec = new BlitExp(loc, new VarExp(loc, tmp), new ThisExp(loc)); - e = Expression.combine(e, ec); - } - ec = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id.p)); - e = Expression.combine(e, ec); - if (sd.dtor) - { - /* Instead of running the destructor on s, run it - * on tmp. This avoids needing to copy tmp back in to s. - */ - Expression ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd.dtor, false); - ec2 = new CallExp(loc, ec2); - e = Expression.combine(e, ec2); - } - } - else - { - /* Do memberwise copy. - * - * If sd is a nested struct, its vthis field assignment is: - * 1. If it's nested in a class, it's a rebind of class reference. - * 2. If it's nested in a function or struct, it's an update of void*. - * In both cases, it will change the parent context. - */ - //printf("\tmemberwise copy\n"); - for (size_t i = 0; i < sd.fields.dim; i++) - { - VarDeclaration v = sd.fields[i]; - // this.v = s.v; - auto ec = new AssignExp(loc, - new DotVarExp(loc, new ThisExp(loc), v), - new DotVarExp(loc, new IdentifierExp(loc, Id.p), v)); - e = Expression.combine(e, ec); - } - } - if (e) - { - Statement s1 = new ExpStatement(loc, e); - /* Add: - * return this; - */ - e = new ThisExp(loc); - Statement s2 = new ReturnStatement(loc, e); - fop.fbody = new CompoundStatement(loc, s1, s2); - tf.isreturn = true; - } - sd.members.push(fop); - fop.addMember(sc, sd); - sd.hasIdentityAssign = true; // temporary mark identity assignable - uint errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. - Scope* sc2 = sc.push(); - sc2.stc = 0; - sc2.linkage = LINKd; - fop.semantic(sc2); - fop.semantic2(sc2); - // https://issues.dlang.org/show_bug.cgi?id=15044 - // fop.semantic3 isn't run here for lazy forward reference resolution. - - sc2.pop(); - if (global.endGagging(errors)) // if errors happened - { - // Disable generated opAssign, because some members forbid identity assignment. - fop.storage_class |= STCdisable; - fop.fbody = null; // remove fbody which contains the error - } - - //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd.toChars(), (fop.storage_class & STCdisable) != 0); - return fop; -} - -/******************************************* - * We need an opEquals for the struct if - * any fields has an opEquals. - * Generate one if a user-specified one does not exist. - */ -extern (C++) bool needOpEquals(StructDeclaration sd) -{ - //printf("StructDeclaration::needOpEquals() %s\n", sd.toChars()); - if (sd.isUnionDeclaration()) - goto Ldontneed; - if (sd.hasIdentityEquals) - goto Lneed; - /* If any of the fields has an opEquals, then we - * need it too. - */ - for (size_t i = 0; i < sd.fields.dim; i++) - { - VarDeclaration v = sd.fields[i]; - if (v.storage_class & STCref) - continue; - if (v.overlapped) - continue; - Type tv = v.type.toBasetype(); - auto tvbase = tv.baseElemOf(); - if (tvbase.ty == Tstruct) - { - TypeStruct ts = cast(TypeStruct)tvbase; - if (ts.sym.isUnionDeclaration()) - continue; - if (needOpEquals(ts.sym)) - goto Lneed; - if (ts.sym.aliasthis) // https://issues.dlang.org/show_bug.cgi?id=14806 - goto Lneed; - } - if (tv.isfloating()) - { - // This is necessray for: - // 1. comparison of +0.0 and -0.0 should be true. - // 2. comparison of NANs should be false always. - goto Lneed; - } - if (tv.ty == Tarray) - goto Lneed; - if (tv.ty == Taarray) - goto Lneed; - if (tv.ty == Tclass) - goto Lneed; - } -Ldontneed: - //printf("\tdontneed\n"); - return false; -Lneed: - //printf("\tneed\n"); - return true; -} - -/******************************************* - * Check given aggregate actually has an identity opEquals or not. - */ -extern (C++) FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) -{ - Dsymbol eq = search_function(ad, Id.eq); - if (eq) - { - /* check identity opEquals exists - */ - scope er = new NullExp(ad.loc, null); // dummy rvalue - scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue - Expressions a; - a.setDim(1); - foreach (i; 0 .. 5) - { - Type tthis = null; // dead-store to prevent spurious warning - final switch (i) - { - case 0: tthis = ad.type; break; - case 1: tthis = ad.type.constOf(); break; - case 2: tthis = ad.type.immutableOf(); break; - case 3: tthis = ad.type.sharedOf(); break; - case 4: tthis = ad.type.sharedConstOf(); break; - } - FuncDeclaration f = null; - const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. - sc = sc.push(); - sc.tinst = null; - sc.minst = null; - foreach (j; 0 .. 2) - { - a[0] = (j == 0 ? er : el); - a[0].type = tthis; - f = resolveFuncCall(ad.loc, sc, eq, null, tthis, &a, 1); - if (f) - break; - } - sc = sc.pop(); - global.endGagging(errors); - if (f) - { - if (f.errors) - return null; - return f; - } - } - } - return null; -} - -/****************************************** - * Build opEquals for struct. - * const bool opEquals(const S s) { ... } - * - * By fixing https://issues.dlang.org/show_bug.cgi?id=3789 - * opEquals is changed to be never implicitly generated. - * Now, struct objects comparison s1 == s2 is translated to: - * s1.tupleof == s2.tupleof - * to calculate structural equality. See EqualExp.op_overload. - */ -extern (C++) FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc) -{ - if (hasIdentityOpEquals(sd, sc)) - { - sd.hasIdentityEquals = true; - } - return null; -} - -/****************************************** - * Build __xopEquals for TypeInfo_Struct - * static bool __xopEquals(ref const S p, ref const S q) - * { - * return p == q; - * } - * - * This is called by TypeInfo.equals(p1, p2). If the struct does not support - * const objects comparison, it will throw "not implemented" Error in runtime. - */ -extern (C++) FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) -{ - if (!needOpEquals(sd)) - return null; // bitwise comparison would work - - //printf("StructDeclaration::buildXopEquals() %s\n", sd.toChars()); - if (Dsymbol eq = search_function(sd, Id.eq)) - { - if (FuncDeclaration fd = eq.isFuncDeclaration()) - { - TypeFunction tfeqptr; - { - Scope scx; - /* const bool opEquals(ref const S s); - */ - auto parameters = new Parameters(); - parameters.push(new Parameter(STCref | STCconst, sd.type, null, null)); - tfeqptr = new TypeFunction(parameters, Type.tbool, 0, LINKd); - tfeqptr.mod = MODconst; - tfeqptr = cast(TypeFunction)tfeqptr.semantic(Loc(), &scx); - } - fd = fd.overloadExactMatch(tfeqptr); - if (fd) - return fd; - } - } - if (!sd.xerreq) - { - // object._xopEquals - Identifier id = Identifier.idPool("_xopEquals"); - Expression e = new IdentifierExp(sd.loc, Id.empty); - e = new DotIdExp(sd.loc, e, Id.object); - e = new DotIdExp(sd.loc, e, id); - e = e.semantic(sc); - Dsymbol s = getDsymbol(e); - assert(s); - sd.xerreq = s.isFuncDeclaration(); - } - Loc declLoc = Loc(); // loc is unnecessary so __xopEquals is never called directly - Loc loc = Loc(); // loc is unnecessary so errors are gagged - auto parameters = new Parameters(); - parameters.push(new Parameter(STCref | STCconst, sd.type, Id.p, null)); - parameters.push(new Parameter(STCref | STCconst, sd.type, Id.q, null)); - auto tf = new TypeFunction(parameters, Type.tbool, 0, LINKd); - Identifier id = Id.xopEquals; - auto fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); - fop.generated = true; - Expression e1 = new IdentifierExp(loc, Id.p); - Expression e2 = new IdentifierExp(loc, Id.q); - Expression e = new EqualExp(TOKequal, loc, e1, e2); - fop.fbody = new ReturnStatement(loc, e); - uint errors = global.startGagging(); // Do not report errors - Scope* sc2 = sc.push(); - sc2.stc = 0; - sc2.linkage = LINKd; - fop.semantic(sc2); - fop.semantic2(sc2); - sc2.pop(); - if (global.endGagging(errors)) // if errors happened - fop = sd.xerreq; - return fop; -} - -/****************************************** - * Build __xopCmp for TypeInfo_Struct - * static bool __xopCmp(ref const S p, ref const S q) - * { - * return p.opCmp(q); - * } - * - * This is called by TypeInfo.compare(p1, p2). If the struct does not support - * const objects comparison, it will throw "not implemented" Error in runtime. - */ -extern (C++) FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) -{ - //printf("StructDeclaration::buildXopCmp() %s\n", toChars()); - if (Dsymbol cmp = search_function(sd, Id.cmp)) - { - if (FuncDeclaration fd = cmp.isFuncDeclaration()) - { - TypeFunction tfcmpptr; - { - Scope scx; - /* const int opCmp(ref const S s); - */ - auto parameters = new Parameters(); - parameters.push(new Parameter(STCref | STCconst, sd.type, null, null)); - tfcmpptr = new TypeFunction(parameters, Type.tint32, 0, LINKd); - tfcmpptr.mod = MODconst; - tfcmpptr = cast(TypeFunction)tfcmpptr.semantic(Loc(), &scx); - } - fd = fd.overloadExactMatch(tfcmpptr); - if (fd) - return fd; - } - } - else - { - version (none) // FIXME: doesn't work for recursive alias this - { - /* Check opCmp member exists. - * Consider 'alias this', but except opDispatch. - */ - Expression e = new DsymbolExp(sd.loc, sd); - e = new DotIdExp(sd.loc, e, Id.cmp); - Scope* sc2 = sc.push(); - e = e.trySemantic(sc2); - sc2.pop(); - if (e) - { - Dsymbol s = null; - switch (e.op) - { - case TOKoverloadset: - s = (cast(OverExp)e).vars; - break; - case TOKscope: - s = (cast(ScopeExp)e).sds; - break; - case TOKvar: - s = (cast(VarExp)e).var; - break; - default: - break; - } - if (!s || s.ident != Id.cmp) - e = null; // there's no valid member 'opCmp' - } - if (!e) - return null; // bitwise comparison would work - /* Essentially, a struct which does not define opCmp is not comparable. - * At this time, typeid(S).compare might be correct that throwing "not implement" Error. - * But implementing it would break existing code, such as: - * - * struct S { int value; } // no opCmp - * int[S] aa; // Currently AA key uses bitwise comparison - * // (It's default behavior of TypeInfo_Strust.compare). - * - * Not sure we should fix this inconsistency, so just keep current behavior. - */ - } - else - { - return null; - } - } - if (!sd.xerrcmp) - { - // object._xopCmp - Identifier id = Identifier.idPool("_xopCmp"); - Expression e = new IdentifierExp(sd.loc, Id.empty); - e = new DotIdExp(sd.loc, e, Id.object); - e = new DotIdExp(sd.loc, e, id); - e = e.semantic(sc); - Dsymbol s = getDsymbol(e); - assert(s); - sd.xerrcmp = s.isFuncDeclaration(); - } - Loc declLoc = Loc(); // loc is unnecessary so __xopCmp is never called directly - Loc loc = Loc(); // loc is unnecessary so errors are gagged - auto parameters = new Parameters(); - parameters.push(new Parameter(STCref | STCconst, sd.type, Id.p, null)); - parameters.push(new Parameter(STCref | STCconst, sd.type, Id.q, null)); - auto tf = new TypeFunction(parameters, Type.tint32, 0, LINKd); - Identifier id = Id.xopCmp; - auto fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); - fop.generated = true; - Expression e1 = new IdentifierExp(loc, Id.p); - Expression e2 = new IdentifierExp(loc, Id.q); - Expression e = new CallExp(loc, new DotIdExp(loc, e2, Id.cmp), e1); - fop.fbody = new ReturnStatement(loc, e); - uint errors = global.startGagging(); // Do not report errors - Scope* sc2 = sc.push(); - sc2.stc = 0; - sc2.linkage = LINKd; - fop.semantic(sc2); - fop.semantic2(sc2); - sc2.pop(); - if (global.endGagging(errors)) // if errors happened - fop = sd.xerrcmp; - return fop; -} - -/******************************************* - * We need a toHash for the struct if - * any fields has a toHash. - * Generate one if a user-specified one does not exist. - */ -private bool needToHash(StructDeclaration sd) -{ - //printf("StructDeclaration::needToHash() %s\n", sd.toChars()); - if (sd.isUnionDeclaration()) - goto Ldontneed; - if (sd.xhash) - goto Lneed; - - /* If any of the fields has an opEquals, then we - * need it too. - */ - for (size_t i = 0; i < sd.fields.dim; i++) - { - VarDeclaration v = sd.fields[i]; - if (v.storage_class & STCref) - continue; - if (v.overlapped) - continue; - Type tv = v.type.toBasetype(); - auto tvbase = tv.baseElemOf(); - if (tvbase.ty == Tstruct) - { - TypeStruct ts = cast(TypeStruct)tvbase; - if (ts.sym.isUnionDeclaration()) - continue; - if (needToHash(ts.sym)) - goto Lneed; - if (ts.sym.aliasthis) // https://issues.dlang.org/show_bug.cgi?id=14948 - goto Lneed; - } - if (tv.isfloating()) - { - // This is necessray for: - // 1. comparison of +0.0 and -0.0 should be true. - goto Lneed; - } - if (tv.ty == Tarray) - goto Lneed; - if (tv.ty == Taarray) - goto Lneed; - if (tv.ty == Tclass) - goto Lneed; - } -Ldontneed: - //printf("\tdontneed\n"); - return false; -Lneed: - //printf("\tneed\n"); - return true; -} - -/****************************************** - * Build __xtoHash for non-bitwise hashing - * static hash_t xtoHash(ref const S p) nothrow @trusted; - */ -extern (C++) FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) -{ - if (Dsymbol s = search_function(sd, Id.tohash)) - { - static __gshared TypeFunction tftohash; - if (!tftohash) - { - tftohash = new TypeFunction(null, Type.thash_t, 0, LINKd); - tftohash.mod = MODconst; - tftohash = cast(TypeFunction)tftohash.merge(); - } - if (FuncDeclaration fd = s.isFuncDeclaration()) - { - fd = fd.overloadExactMatch(tftohash); - if (fd) - return fd; - } - } - if (!needToHash(sd)) - return null; - - //printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars()); - Loc declLoc = Loc(); // loc is unnecessary so __xtoHash is never called directly - Loc loc = Loc(); // internal code should have no loc to prevent coverage - auto parameters = new Parameters(); - parameters.push(new Parameter(STCref | STCconst, sd.type, Id.p, null)); - auto tf = new TypeFunction(parameters, Type.thash_t, 0, LINKd, STCnothrow | STCtrusted); - Identifier id = Id.xtoHash; - auto fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); - fop.generated = true; - - /* Do memberwise hashing. - * - * If sd is a nested struct, and if it's nested in a class, the calculated - * hash value will also contain the result of parent class's toHash(). - */ - const(char)* code = - "size_t h = 0;" ~ - "foreach (i, T; typeof(p.tupleof))" ~ - " h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);" ~ - "return h;"; - fop.fbody = new CompileStatement(loc, new StringExp(loc, cast(char*)code)); - Scope* sc2 = sc.push(); - sc2.stc = 0; - sc2.linkage = LINKd; - fop.semantic(sc2); - fop.semantic2(sc2); - sc2.pop(); - - //printf("%s fop = %s %s\n", sd.toChars(), fop.toChars(), fop.type.toChars()); - return fop; -} - -/***************************************** - * Create inclusive postblit for struct by aggregating - * all the postblits in postblits[] with the postblits for - * all the members. - * Note the close similarity with AggregateDeclaration::buildDtor(), - * and the ordering changes (runs forward instead of backwards). - */ -extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) -{ - //printf("StructDeclaration::buildPostBlit() %s\n", sd.toChars()); - if (sd.isUnionDeclaration()) - return null; - - StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; - Loc declLoc = sd.postblits.dim ? sd.postblits[0].loc : sd.loc; - Loc loc = Loc(); // internal code should have no loc to prevent coverage - - for (size_t i = 0; i < sd.postblits.dim; i++) - { - stc |= sd.postblits[i].storage_class & STCdisable; - } - - auto a = new Statements(); - for (size_t i = 0; i < sd.fields.dim && !(stc & STCdisable); i++) - { - auto v = sd.fields[i]; - if (v.storage_class & STCref) - continue; - if (v.overlapped) - continue; - Type tv = v.type.baseElemOf(); - if (tv.ty != Tstruct) - continue; - auto sdv = (cast(TypeStruct)tv).sym; - if (!sdv.postblit) - continue; - assert(!sdv.isUnionDeclaration()); - sdv.postblit.functionSemantic(); - - stc = mergeFuncAttrs(stc, sdv.postblit); - stc = mergeFuncAttrs(stc, sdv.dtor); - if (stc & STCdisable) - { - a.setDim(0); - break; - } - - Expression ex; - tv = v.type.toBasetype(); - if (tv.ty == Tstruct) - { - // this.v.__xpostblit() - - ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v); - - // This is a hack so we can call postblits on const/immutable objects. - ex = new AddrExp(loc, ex); - ex = new CastExp(loc, ex, v.type.mutableOf().pointerTo()); - ex = new PtrExp(loc, ex); - if (stc & STCsafe) - stc = (stc & ~STCsafe) | STCtrusted; - - ex = new DotVarExp(loc, ex, sdv.postblit, false); - ex = new CallExp(loc, ex); - } - else - { - // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n]) - - uinteger_t n = 1; - while (tv.ty == Tsarray) - { - n *= (cast(TypeSArray)tv).dim.toUInteger(); - tv = tv.nextOf().toBasetype(); - } - if (n == 0) - continue; - - ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v); - - // This is a hack so we can call postblits on const/immutable objects. - ex = new DotIdExp(loc, ex, Id.ptr); - ex = new CastExp(loc, ex, sdv.type.pointerTo()); - if (stc & STCsafe) - stc = (stc & ~STCsafe) | STCtrusted; - - ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), - new IntegerExp(loc, n, Type.tsize_t)); - // Prevent redundant bounds check - (cast(SliceExp)ex).upperIsInBounds = true; - (cast(SliceExp)ex).lowerIsLessThanUpper = true; - ex = new CallExp(loc, new IdentifierExp(loc, Id._ArrayPostblit), ex); - } - a.push(new ExpStatement(loc, ex)); // combine in forward order - - /* https://issues.dlang.org/show_bug.cgi?id=10972 - * When the following field postblit calls fail, - * this field should be destructed for Exception Safety. - */ - if (!sdv.dtor) - continue; - sdv.dtor.functionSemantic(); - - tv = v.type.toBasetype(); - if (tv.ty == Tstruct) - { - // this.v.__xdtor() - - ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v); - - // This is a hack so we can call destructors on const/immutable objects. - ex = new AddrExp(loc, ex); - ex = new CastExp(loc, ex, v.type.mutableOf().pointerTo()); - ex = new PtrExp(loc, ex); - if (stc & STCsafe) - stc = (stc & ~STCsafe) | STCtrusted; - - ex = new DotVarExp(loc, ex, sdv.dtor, false); - ex = new CallExp(loc, ex); - } - else - { - // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) - - uinteger_t n = 1; - while (tv.ty == Tsarray) - { - n *= (cast(TypeSArray)tv).dim.toUInteger(); - tv = tv.nextOf().toBasetype(); - } - //if (n == 0) - // continue; - - ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v); - - // This is a hack so we can call destructors on const/immutable objects. - ex = new DotIdExp(loc, ex, Id.ptr); - ex = new CastExp(loc, ex, sdv.type.pointerTo()); - if (stc & STCsafe) - stc = (stc & ~STCsafe) | STCtrusted; - - ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), - new IntegerExp(loc, n, Type.tsize_t)); - // Prevent redundant bounds check - (cast(SliceExp)ex).upperIsInBounds = true; - (cast(SliceExp)ex).lowerIsLessThanUpper = true; - - ex = new CallExp(loc, new IdentifierExp(loc, Id._ArrayDtor), ex); - } - a.push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex))); - } - - // Build our own "postblit" which executes a, but only if needed. - if (a.dim || (stc & STCdisable)) - { - //printf("Building __fieldPostBlit()\n"); - auto dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id.__fieldPostblit); - dd.generated = true; - dd.storage_class |= STCinference; - dd.fbody = (stc & STCdisable) ? null : new CompoundStatement(loc, a); - sd.postblits.shift(dd); - sd.members.push(dd); - dd.semantic(sc); - } - - FuncDeclaration xpostblit = null; - switch (sd.postblits.dim) - { - case 0: - break; - - case 1: - xpostblit = sd.postblits[0]; - break; - - default: - Expression e = null; - stc = STCsafe | STCnothrow | STCpure | STCnogc; - for (size_t i = 0; i < sd.postblits.dim; i++) - { - auto fd = sd.postblits[i]; - stc = mergeFuncAttrs(stc, fd); - if (stc & STCdisable) - { - e = null; - break; - } - Expression ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, fd, false); - ex = new CallExp(loc, ex); - e = Expression.combine(e, ex); - } - auto dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id.__aggrPostblit); - dd.generated = true; - dd.storage_class |= STCinference; - dd.fbody = new ExpStatement(loc, e); - sd.members.push(dd); - dd.semantic(sc); - xpostblit = dd; - break; - } - - // Add an __xpostblit alias to make the inclusive postblit accessible - if (xpostblit) - { - auto _alias = new AliasDeclaration(Loc(), Id.__xpostblit, xpostblit); - _alias.semantic(sc); - sd.members.push(_alias); - _alias.addMember(sc, sd); // add to symbol table - } - return xpostblit; -} - -/***************************************** - * Create inclusive destructor for struct/class by aggregating - * all the destructors in dtors[] with the destructors for - * all the members. - * Note the close similarity with StructDeclaration::buildPostBlit(), - * and the ordering changes (runs backward instead of forwards). - */ -extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) -{ - //printf("AggregateDeclaration::buildDtor() %s\n", ad.toChars()); - if (ad.isUnionDeclaration()) - return null; - - StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; - Loc declLoc = ad.dtors.dim ? ad.dtors[0].loc : ad.loc; - Loc loc = Loc(); // internal code should have no loc to prevent coverage - - Expression e = null; - for (size_t i = 0; i < ad.fields.dim; i++) - { - auto v = ad.fields[i]; - if (v.storage_class & STCref) - continue; - if (v.overlapped) - continue; - auto tv = v.type.baseElemOf(); - if (tv.ty != Tstruct) - continue; - auto sdv = (cast(TypeStruct)tv).sym; - if (!sdv.dtor) - continue; - sdv.dtor.functionSemantic(); - - stc = mergeFuncAttrs(stc, sdv.dtor); - if (stc & STCdisable) - { - e = null; - break; - } - - Expression ex; - tv = v.type.toBasetype(); - if (tv.ty == Tstruct) - { - // this.v.__xdtor() - - ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v); - - // This is a hack so we can call destructors on const/immutable objects. - ex = new AddrExp(loc, ex); - ex = new CastExp(loc, ex, v.type.mutableOf().pointerTo()); - ex = new PtrExp(loc, ex); - if (stc & STCsafe) - stc = (stc & ~STCsafe) | STCtrusted; - - ex = new DotVarExp(loc, ex, sdv.dtor, false); - ex = new CallExp(loc, ex); - } - else - { - // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) - - uinteger_t n = 1; - while (tv.ty == Tsarray) - { - n *= (cast(TypeSArray)tv).dim.toUInteger(); - tv = tv.nextOf().toBasetype(); - } - if (n == 0) - continue; - - ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v); - - // This is a hack so we can call destructors on const/immutable objects. - ex = new DotIdExp(loc, ex, Id.ptr); - ex = new CastExp(loc, ex, sdv.type.pointerTo()); - if (stc & STCsafe) - stc = (stc & ~STCsafe) | STCtrusted; - - ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), - new IntegerExp(loc, n, Type.tsize_t)); - // Prevent redundant bounds check - (cast(SliceExp)ex).upperIsInBounds = true; - (cast(SliceExp)ex).lowerIsLessThanUpper = true; - - ex = new CallExp(loc, new IdentifierExp(loc, Id._ArrayDtor), ex); - } - e = Expression.combine(ex, e); // combine in reverse order - } - - /* Build our own "destructor" which executes e - */ - if (e || (stc & STCdisable)) - { - //printf("Building __fieldDtor()\n"); - auto dd = new DtorDeclaration(declLoc, Loc(), stc, Id.__fieldDtor); - dd.generated = true; - dd.storage_class |= STCinference; - dd.fbody = new ExpStatement(loc, e); - ad.dtors.shift(dd); - ad.members.push(dd); - dd.semantic(sc); - } - - FuncDeclaration xdtor = null; - switch (ad.dtors.dim) - { - case 0: - break; - - case 1: - xdtor = ad.dtors[0]; - break; - - default: - e = null; - stc = STCsafe | STCnothrow | STCpure | STCnogc; - for (size_t i = 0; i < ad.dtors.dim; i++) - { - FuncDeclaration fd = ad.dtors[i]; - stc = mergeFuncAttrs(stc, fd); - if (stc & STCdisable) - { - e = null; - break; - } - Expression ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, fd, false); - ex = new CallExp(loc, ex); - e = Expression.combine(ex, e); - } - auto dd = new DtorDeclaration(declLoc, Loc(), stc, Id.__aggrDtor); - dd.generated = true; - dd.storage_class |= STCinference; - dd.fbody = new ExpStatement(loc, e); - ad.members.push(dd); - dd.semantic(sc); - xdtor = dd; - break; - } - - // Add an __xdtor alias to make the inclusive dtor accessible - if (xdtor) - { - auto _alias = new AliasDeclaration(Loc(), Id.__xdtor, xdtor); - _alias.semantic(sc); - ad.members.push(_alias); - _alias.addMember(sc, ad); // add to symbol table - } - return xdtor; -} - -/****************************************** - * Create inclusive invariant for struct/class by aggregating - * all the invariants in invs[]. - * void __invariant() const [pure nothrow @trusted] - * { - * invs[0](), invs[1](), ...; - * } - */ -extern (C++) FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc) -{ - StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; - Loc declLoc = ad.loc; - Loc loc = Loc(); // internal code should have no loc to prevent coverage - switch (ad.invs.dim) - { - case 0: - return null; - case 1: - // Don't return invs[0] so it has uniquely generated name. - /* fall through */ - default: - Expression e = null; - StorageClass stcx = 0; - for (size_t i = 0; i < ad.invs.dim; i++) - { - stc = mergeFuncAttrs(stc, ad.invs[i]); - if (stc & STCdisable) - { - // What should do? - } - StorageClass stcy = (ad.invs[i].storage_class & STCsynchronized) | (ad.invs[i].type.mod & MODshared ? STCshared : 0); - if (i == 0) - stcx = stcy; - else if (stcx ^ stcy) - { - version (all) - { - // currently rejects - ad.error(ad.invs[i].loc, "mixing invariants with shared/synchronized differene is not supported"); - e = null; - break; - } - } - e = Expression.combine(e, new CallExp(loc, new VarExp(loc, ad.invs[i], false))); - } - auto inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id.classInvariant, new ExpStatement(loc, e)); - ad.members.push(inv); - inv.semantic(sc); - return inv; - } -} diff -Nru ldc-1.6.0/ddmd/complex.d ldc-1.8.0/ddmd/complex.d --- ldc-1.6.0/ddmd/complex.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/complex.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/complex.d, _complex.d) - */ - -module ddmd.complex; - -// Online documentation: https://dlang.org/phobos/ddmd_complex.html - -import ddmd.root.ctfloat; - -struct complex_t -{ - real_t re; - real_t im; - - this() @disable; - - this(real_t re) - { - this(re, CTFloat.zero); - } - - this(real_t re, real_t im) - { - this.re = re; - this.im = im; - } - - complex_t opAdd(complex_t y) - { - return complex_t(re + y.re, im + y.im); - } - - complex_t opSub(complex_t y) - { - return complex_t(re - y.re, im - y.im); - } - - complex_t opNeg() - { - return complex_t(-re, -im); - } - - complex_t opMul(complex_t y) - { - return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); - } - - complex_t opMul_r(real_t x) - { - return complex_t(x) * this; - } - - complex_t opMul(real_t y) - { - return this * complex_t(y); - } - - complex_t opDiv(real_t y) - { - return this / complex_t(y); - } - - complex_t opDiv(complex_t y) - { - if (CTFloat.fabs(y.re) < CTFloat.fabs(y.im)) - { - const r = y.re / y.im; - const den = y.im + r * y.re; - return complex_t((re * r + im) / den, (im * r - re) / den); - } - else - { - const r = y.im / y.re; - const den = y.re + r * y.im; - return complex_t((re + r * im) / den, (im - r * re) / den); - } - } - - bool opCast(T : bool)() - { - return re || im; - } - - int opEquals(complex_t y) - { - return re == y.re && im == y.im; - } -} - -extern (C++) real_t creall(complex_t x) -{ - return x.re; -} - -extern (C++) real_t cimagl(complex_t x) -{ - return x.im; -} diff -Nru ldc-1.6.0/ddmd/complex_t.h ldc-1.8.0/ddmd/complex_t.h --- ldc-1.6.0/ddmd/complex_t.h 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/complex_t.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (c) 1999-2016 by Digital Mars - * All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/dlang/dmd/blob/master/src/complex_t.h - */ - -#ifndef DMD_COMPLEX_T_H -#define DMD_COMPLEX_T_H - -#include "ctfloat.h" - -/* Roll our own complex type for compilers that don't support complex - */ - -struct complex_t -{ - real_t re; - real_t im; - - complex_t(real_t re) : re(re), im(0) {} - complex_t(real_t re, real_t im) : re(re), im(im) {} - - complex_t operator + (complex_t y) { return complex_t(re + y.re, im + y.im); } - complex_t operator - (complex_t y) { return complex_t(re - y.re, im - y.im); } - complex_t operator - () { return complex_t(-re, -im); } - complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); } - - complex_t operator / (complex_t y) - { - if (CTFloat::fabs(y.re) < CTFloat::fabs(y.im)) - { - real_t r = y.re / y.im; - real_t den = y.im + r * y.re; - return complex_t((re * r + im) / den, - (im * r - re) / den); - } - else - { - real_t r = y.im / y.re; - real_t den = y.re + r * y.im; - return complex_t((re + r * im) / den, - (im - r * re) / den); - } - } - - operator bool () { return re || im; } - - int operator == (complex_t y) { return re == y.re && im == y.im; } - int operator != (complex_t y) { return re != y.re || im != y.im; } - -private: - complex_t() : re(0), im(0) {} -}; - -inline complex_t operator * (real_t x, complex_t y) { return complex_t(x) * y; } -inline complex_t operator * (complex_t x, real_t y) { return x * complex_t(y); } -inline complex_t operator / (complex_t x, real_t y) { return x / complex_t(y); } - - -inline real_t creall(complex_t x) -{ - return x.re; -} - -inline real_t cimagl(complex_t x) -{ - return x.im; -} - -#endif diff -Nru ldc-1.6.0/ddmd/cond.d ldc-1.8.0/ddmd/cond.d --- ldc-1.6.0/ddmd/cond.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/cond.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,958 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/cond.d, _cond.d) - */ - -module ddmd.cond; - -// Online documentation: https://dlang.org/phobos/ddmd_cond.html - -import core.stdc.string; -import ddmd.arraytypes; -import ddmd.dmodule; -import ddmd.dscope; -import ddmd.dsymbol; -import ddmd.errors; -import ddmd.expression; -import ddmd.expressionsem; -import ddmd.globals; -import ddmd.identifier; -import ddmd.mtype; -import ddmd.root.outbuffer; -import ddmd.root.rootobject; -import ddmd.tokens; -import ddmd.utils; -import ddmd.visitor; -import ddmd.id; -import ddmd.statement; -import ddmd.declaration; -import ddmd.dstruct; -import ddmd.func; - -/*********************************************************** - */ -extern (C++) abstract class Condition : RootObject -{ - Loc loc; - // 0: not computed yet - // 1: include - // 2: do not include - int inc; - - override final DYNCAST dyncast() const - { - return DYNCAST.condition; - } - - final extern (D) this(Loc loc) - { - this.loc = loc; - } - - abstract Condition syntaxCopy(); - - abstract int include(Scope* sc, ScopeDsymbol sds); - - DebugCondition isDebugCondition() - { - return null; - } - - void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - * Implements common functionality for StaticForeachDeclaration and - * StaticForeachStatement This performs the necessary lowerings before - * ddmd.statementsem.makeTupleForeach can be used to expand the - * corresponding `static foreach` declaration or statement. - */ - -extern (C++) final class StaticForeach : RootObject -{ - extern(D) static immutable tupleFieldName = "tuple"; // used in lowering - - Loc loc; - - /*************** - * Not `null` iff the `static foreach` is over an aggregate. In - * this case, it contains the corresponding ForeachStatement. For - * StaticForeachDeclaration, the body is `null`. - */ - ForeachStatement aggrfe; - /*************** - * Not `null` iff the `static foreach` is over a range. Exactly - * one of the `aggrefe` and `rangefe` fields is not null. See - * `aggrfe` field for more details. - */ - ForeachRangeStatement rangefe; - - /*************** - * true if it is necessary to expand a tuple into multiple - * variables (see lowerNonArrayAggregate). - */ - bool needExpansion = false; - - final extern (D) this(Loc loc,ForeachStatement aggrfe,ForeachRangeStatement rangefe) - in - { - assert(!!aggrfe ^ !!rangefe); - } - body - { - this.loc = loc; - this.aggrfe = aggrfe; - this.rangefe = rangefe; - } - - StaticForeach syntaxCopy() - { - return new StaticForeach( - loc, - aggrfe ? cast(ForeachStatement)aggrfe.syntaxCopy() : null, - rangefe ? cast(ForeachRangeStatement)rangefe.syntaxCopy() : null - ); - } - - /***************************************** - * Turn an aggregate which is an array into an expression tuple - * of its elements. I.e., lower - * static foreach (x; [1, 2, 3, 4]) { ... } - * to - * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... } - */ - private extern(D) void lowerArrayAggregate(Scope* sc) - { - auto aggr = aggrfe.aggr; - Expression el = new ArrayLengthExp(aggr.loc, aggr); - sc = sc.startCTFE(); - el = el.semantic(sc); - sc = sc.endCTFE(); - el = el.optimize(WANTvalue); - el = el.ctfeInterpret(); - if (el.op == TOKint64) - { - dinteger_t length = el.toInteger(); - auto es = new Expressions(); - foreach (i; 0 .. length) - { - auto index = new IntegerExp(loc, i, Type.tsize_t); - auto value = new IndexExp(aggr.loc, aggr, index); - es.push(value); - } - aggrfe.aggr = new TupleExp(aggr.loc, es); - aggrfe.aggr = aggrfe.aggr.semantic(sc); - aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue); - } - else - { - aggrfe.aggr = new ErrorExp(); - } - } - - /***************************************** - * Wrap a statement into a function literal and call it. - * - * Params: - * loc = The source location. - * s = The statement. - * Returns: - * AST of the expression `(){ s; }()` with location loc. - */ - private extern(D) Expression wrapAndCall(Loc loc, Statement s) - { - auto tf = new TypeFunction(new Parameters(), null, 0, LINK.def, 0); - auto fd = new FuncLiteralDeclaration(loc, loc, tf, TOKreserved, null); - fd.fbody = s; - auto fe = new FuncExp(loc, fd); - auto ce = new CallExp(loc, fe, new Expressions()); - return ce; - } - - /***************************************** - * Create a `foreach` statement from `aggrefe/rangefe` with given - * `foreach` variables and body `s`. - * - * Params: - * loc = The source location. - * parameters = The foreach variables. - * s = The `foreach` body. - * Returns: - * `foreach (parameters; aggregate) s;` or - * `foreach (parameters; lower .. upper) s;` - * Where aggregate/lower, upper are as for the current StaticForeach. - */ - private extern(D) Statement createForeach(Loc loc, Parameters* parameters, Statement s) - { - if (aggrfe) - { - return new ForeachStatement(loc, aggrfe.op, parameters, aggrfe.aggr.syntaxCopy(), s, loc); - } - else - { - assert(rangefe && parameters.dim == 1); - return new ForeachRangeStatement(loc, rangefe.op, (*parameters)[0], rangefe.lwr.syntaxCopy(), rangefe.upr.syntaxCopy(), s, loc); - } - } - - /***************************************** - * For a `static foreach` with multiple loop variables, the - * aggregate is lowered to an array of tuples. As D does not have - * built-in tuples, we need a suitable tuple type. This generates - * a `struct` that serves as the tuple type. This type is only - * used during CTFE and hence its typeinfo will not go to the - * object file. - * - * Params: - * loc = The source location. - * e = The expressions we wish to store in the tuple. - * sc = The current scope. - * Returns: - * A struct type of the form - * struct Tuple - * { - * typeof(AliasSeq!(e)) tuple; - * } - */ - - private extern(D) TypeStruct createTupleType(Loc loc, Expressions* e, Scope* sc) - { // TODO: move to druntime? - auto sid = Identifier.generateId("Tuple"); - auto sdecl = new StructDeclaration(loc, sid, false); - sdecl.storage_class |= STCstatic; - sdecl.members = new Dsymbols(); - auto fid = Identifier.idPool(tupleFieldName.ptr, tupleFieldName.length); - auto ty = new TypeTypeof(loc, new TupleExp(loc, e)); - sdecl.members.push(new VarDeclaration(loc, ty, fid, null, 0)); - auto r = cast(TypeStruct)sdecl.type; - r.vtinfo = TypeInfoStructDeclaration.create(r); // prevent typeinfo from going to object file - return r; - } - - /***************************************** - * Create the AST for an instantiation of a suitable tuple type. - * - * Params: - * loc = The source location. - * type = A Tuple type, created with createTupleType. - * e = The expressions we wish to store in the tuple. - * Returns: - * An AST for the expression `Tuple(e)`. - */ - - private extern(D) Expression createTuple(Loc loc, TypeStruct type, Expressions* e) - { // TODO: move to druntime? - return new CallExp(loc, new TypeExp(loc, type), e); - } - - - /***************************************** - * Lower any aggregate that is not an array to an array using a - * regular foreach loop within CTFE. If there are multiple - * `static foreach` loop variables, an array of tuples is - * generated. In thise case, the field `needExpansion` is set to - * true to indicate that the static foreach loop expansion will - * need to expand the tuples into multiple variables. - * - * For example, `static foreach (x; range) { ... }` is lowered to: - * - * static foreach (x; { - * typeof({ - * foreach (x; range) return x; - * }())[] __res; - * foreach (x; range) __res ~= x; - * return __res; - * }()) { ... } - * - * Finally, call `lowerArrayAggregate` to turn the produced - * array into an expression tuple. - * - * Params: - * sc = The current scope. - */ - - private void lowerNonArrayAggregate(Scope* sc) - { - auto nvars = aggrfe ? aggrfe.parameters.dim : 1; - auto aloc = aggrfe ? aggrfe.aggr.loc : rangefe.lwr.loc; - // We need three sets of foreach loop variables because the - // lowering contains three foreach loops. - Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()]; - foreach (i; 0 .. nvars) - { - foreach (params; pparams) - { - auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm; - params.push(new Parameter(p.storageClass, p.type, p.ident, null)); - } - } - Expression[2] res; - TypeStruct tplty = null; - if (nvars == 1) // only one `static foreach` variable, generate identifiers. - { - foreach (i; 0 .. 2) - { - res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident); - } - } - else // multiple `static foreach` variables, generate tuples. - { - foreach (i; 0 .. 2) - { - auto e = new Expressions(); - foreach (j; 0 .. pparams[0].dim) - { - auto p = (*pparams[i])[j]; - e.push(new IdentifierExp(aloc, p.ident)); - } - if (!tplty) - { - tplty = createTupleType(aloc, e, sc); - } - res[i] = createTuple(aloc, tplty, e); - } - needExpansion = true; // need to expand the tuples later - } - // generate remaining code for the new aggregate which is an - // array (see documentation comment). - if (rangefe) - { - sc = sc.startCTFE(); - rangefe.lwr = rangefe.lwr.semantic(sc); - rangefe.lwr = resolveProperties(sc, rangefe.lwr); - rangefe.upr = rangefe.upr.semantic(sc); - rangefe.upr = resolveProperties(sc, rangefe.upr); - sc = sc.endCTFE(); - rangefe.lwr = rangefe.lwr.optimize(WANTvalue); - rangefe.lwr = rangefe.lwr.ctfeInterpret(); - rangefe.upr = rangefe.upr.optimize(WANTvalue); - rangefe.upr = rangefe.upr.ctfeInterpret(); - } - auto s1 = new Statements(); - auto sfe = new Statements(); - if (tplty) sfe.push(new ExpStatement(loc, tplty.sym)); - sfe.push(new ReturnStatement(aloc, res[0])); - s1.push(createForeach(aloc, pparams[0], new CompoundStatement(aloc, sfe))); - s1.push(new ExpStatement(aloc, new AssertExp(aloc, new IntegerExp(aloc, 0, Type.tint32)))); - auto ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1))); - auto aty = ety.arrayOf(); - auto idres = Identifier.generateId("__res"); - auto vard = new VarDeclaration(aloc, aty, idres, null); - auto s2 = new Statements(); - s2.push(new ExpStatement(aloc, vard)); - auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]); - s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass))); - s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres))); - auto aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2)); - sc = sc.startCTFE(); - aggr = aggr.semantic(sc); - aggr = resolveProperties(sc, aggr); - sc = sc.endCTFE(); - aggr = aggr.optimize(WANTvalue); - aggr = aggr.ctfeInterpret(); - - assert(!!aggrfe ^ !!rangefe); - aggrfe = new ForeachStatement(loc, TOKforeach, pparams[2], aggr, - aggrfe ? aggrfe._body : rangefe._body, - aggrfe ? aggrfe.endloc : rangefe.endloc); - rangefe = null; - lowerArrayAggregate(sc); // finally, turn generated array into expression tuple - } - - /***************************************** - * Perform `static foreach` lowerings that are necessary in order - * to finally expand the `static foreach` using - * `ddmd.statementsem.makeTupleForeach`. - */ - final extern(D) void prepare(Scope* sc) - in - { - assert(sc); - } - body - { - if (aggrfe) - { - sc = sc.startCTFE(); - aggrfe.aggr = aggrfe.aggr.semantic(sc); - sc = sc.endCTFE(); - aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue); - auto tab = aggrfe.aggr.type.toBasetype(); - if (tab.ty != Ttuple) - { - aggrfe.aggr = aggrfe.aggr.ctfeInterpret(); - } - } - - if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror) - { - return; - } - - if (!ready()) - { - if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray) - { - lowerArrayAggregate(sc); - } - else - { - lowerNonArrayAggregate(sc); - } - } - } - - /***************************************** - * Returns: - * `true` iff ready to call `ddmd.statementsem.makeTupleForeach`. - */ - final extern(D) bool ready() - { - return aggrfe && aggrfe.aggr && aggrfe.aggr.type.toBasetype().ty == Ttuple; - } -} - -/*********************************************************** - */ -extern (C++) class DVCondition : Condition -{ - uint level; - Identifier ident; - Module mod; - - final extern (D) this(Module mod, uint level, Identifier ident) - { - super(Loc()); - this.mod = mod; - this.level = level; - this.ident = ident; - } - - override final Condition syntaxCopy() - { - return this; // don't need to copy - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - */ -extern (C++) final class DebugCondition : DVCondition -{ - /** - * Set the global debug level - * - * Only called from the driver - * - * Params: - * level = Integer literal to set the global version to - */ - static void setGlobalLevel(uint level) - { - global.params.debuglevel = level; - } - - - /** - * Add an user-supplied identifier to the list of global debug identifiers - * - * Can be called from either the driver or a `debug = Ident;` statement. - * Unlike version identifier, there isn't any reserved debug identifier - * so no validation takes place. - * - * Params: - * ident = identifier to add - */ - deprecated("Kept for C++ compat - Use the string overload instead") - static void addGlobalIdent(const(char)* ident) - { - addGlobalIdent(ident[0 .. ident.strlen]); - } - - /// Ditto - extern(D) static void addGlobalIdent(string ident) - { - // Overload necessary for string literals - addGlobalIdent(cast(const(char)[])ident); - } - - - /// Ditto - extern(D) static void addGlobalIdent(const(char)[] ident) - { - if (!global.params.debugids) - global.params.debugids = new Strings(); - global.params.debugids.push(cast(char*)ident); - } - - - /** - * Instantiate a new `DebugCondition` - * - * Params: - * mod = Module this node belongs to - * level = Minimum global level this condition needs to pass. - * Only used if `ident` is `null`. - * ident = Identifier required for this condition to pass. - * If `null`, this conditiion will use an integer level. - */ - extern (D) this(Module mod, uint level, Identifier ident) - { - super(mod, level, ident); - } - - override int include(Scope* sc, ScopeDsymbol sds) - { - //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); - if (inc == 0) - { - inc = 2; - bool definedInModule = false; - if (ident) - { - if (findCondition(mod.debugids, ident)) - { - inc = 1; - definedInModule = true; - } - else if (findCondition(global.params.debugids, ident)) - inc = 1; - else - { - if (!mod.debugidsNot) - mod.debugidsNot = new Strings(); - mod.debugidsNot.push(ident.toChars()); - } - } - else if (level <= global.params.debuglevel || level <= mod.debuglevel) - inc = 1; - if (!definedInModule) - printDepsConditional(sc, this, "depsDebug "); - } - return (inc == 1); - } - - override DebugCondition isDebugCondition() - { - return this; - } - - override void accept(Visitor v) - { - v.visit(this); - } - - override const(char)* toChars() - { - return ident ? ident.toChars() : "debug".ptr; - } -} - -/** - * Node to represent a version condition - * - * A version condition is of the form: - * --- - * version (Identifier) - * --- - * In user code. - * This class also provides means to add version identifier - * to the list of global (cross module) identifiers. - */ -extern (C++) final class VersionCondition : DVCondition -{ - /** - * Set the global version level - * - * Only called from the driver - * - * Params: - * level = Integer literal to set the global version to - */ - static void setGlobalLevel(uint level) - { - global.params.versionlevel = level; - } - - /** - * Check if a given version identifier is reserved. - * - * Reserved identifier are the one documented below or - * those starting with 'D_'. - * - * Params: - * ident = identifier being checked - * - * Returns: - * `true` if it is reserved, `false` otherwise - */ - extern(D) private static bool isReserved(const(char)[] ident) - { - // This list doesn't include "D_*" versions, see the last return - static immutable string[] reserved = - [ - "DigitalMars", - "GNU", - "LDC", - "SDC", - "Windows", - "Win32", - "Win64", - "linux", - "OSX", - "iOS", - "TVOS", - "WatchOS", - "FreeBSD", - "OpenBSD", - "NetBSD", - "DragonFlyBSD", - "BSD", - "Solaris", - "Posix", - "AIX", - "Haiku", - "SkyOS", - "SysV3", - "SysV4", - "Hurd", - "Android", - "PlayStation", - "PlayStation4", - "Cygwin", - "MinGW", - "FreeStanding", - "X86", - "X86_64", - "ARM", - "ARM_Thumb", - "ARM_SoftFloat", - "ARM_SoftFP", - "ARM_HardFloat", - "AArch64", - "Epiphany", - "PPC", - "PPC_SoftFloat", - "PPC_HardFloat", - "PPC64", - "IA64", - "MIPS32", - "MIPS64", - "MIPS_O32", - "MIPS_N32", - "MIPS_O64", - "MIPS_N64", - "MIPS_EABI", - "MIPS_SoftFloat", - "MIPS_HardFloat", - "MSP430", - "NVPTX", - "NVPTX64", - "RISCV32", - "RISCV64", - "SPARC", - "SPARC_V8Plus", - "SPARC_SoftFloat", - "SPARC_HardFloat", - "SPARC64", - "S390", - "S390X", - "SystemZ", - "HPPA", - "HPPA64", - "SH", - "Alpha", - "Alpha_SoftFloat", - "Alpha_HardFloat", - "LittleEndian", - "BigEndian", - "ELFv1", - "ELFv2", - "CRuntime_Bionic", - "CRuntime_DigitalMars", - "CRuntime_Glibc", - "CRuntime_Microsoft", - "CRuntime_Musl", - "CRuntime_UClibc", - "unittest", - "assert", - "all", - "none" - ]; - foreach (r; reserved) - { - if (ident == r) - return true; - } - return (ident.length >= 2 && ident[0 .. 2] == "D_"); - } - - /** - * Raises an error if a version identifier is reserved. - * - * Called when setting a version identifier, e.g. `-version=identifier` - * parameter to the compiler or `version = Foo` in user code. - * - * Params: - * loc = Where the identifier is set - * ident = identifier being checked (ident[$] must be '\0') - */ - extern(D) static void checkReserved(Loc loc, const(char)[] ident) - { - if (isReserved(ident)) - error(loc, "version identifier `%s` is reserved and cannot be set", - ident.ptr); - } - - /** - * Add an user-supplied global identifier to the list - * - * Only called from the driver for `-version=Ident` parameters. - * Will raise an error if the identifier is reserved. - * - * Params: - * ident = identifier to add - */ - deprecated("Kept for C++ compat - Use the string overload instead") - static void addGlobalIdent(const(char)* ident) - { - addGlobalIdent(ident[0 .. ident.strlen]); - } - - /// Ditto - extern(D) static void addGlobalIdent(string ident) - { - // Overload necessary for string literals - addGlobalIdent(cast(const(char)[])ident); - } - - - /// Ditto - extern(D) static void addGlobalIdent(const(char)[] ident) - { - checkReserved(Loc(), ident); - addPredefinedGlobalIdent(ident); - } - - /** - * Add any global identifier to the list, without checking - * if it's predefined - * - * Only called from the driver after platform detection, - * and internally. - * - * Params: - * ident = identifier to add (ident[$] must be '\0') - */ - deprecated("Kept for C++ compat - Use the string overload instead") - static void addPredefinedGlobalIdent(const(char)* ident) - { - addPredefinedGlobalIdent(ident[0 .. ident.strlen]); - } - - /// Ditto - extern(D) static void addPredefinedGlobalIdent(string ident) - { - // Forward: Overload necessary for string literal - addPredefinedGlobalIdent(cast(const(char)[])ident); - } - - - /// Ditto - extern(D) static void addPredefinedGlobalIdent(const(char)[] ident) - { - if (!global.params.versionids) - global.params.versionids = new Strings(); - global.params.versionids.push(cast(char*)ident); - } - - /** - * Instantiate a new `VersionCondition` - * - * Params: - * mod = Module this node belongs to - * level = Minimum global level this condition needs to pass. - * Only used if `ident` is `null`. - * ident = Identifier required for this condition to pass. - * If `null`, this conditiion will use an integer level. - */ - extern (D) this(Module mod, uint level, Identifier ident) - { - super(mod, level, ident); - } - - override int include(Scope* sc, ScopeDsymbol sds) - { - //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); - //if (ident) printf("\tident = '%s'\n", ident.toChars()); - if (inc == 0) - { - inc = 2; - bool definedInModule = false; - if (ident) - { - if (findCondition(mod.versionids, ident)) - { - inc = 1; - definedInModule = true; - } - else if (findCondition(global.params.versionids, ident)) - inc = 1; - else - { - if (!mod.versionidsNot) - mod.versionidsNot = new Strings(); - mod.versionidsNot.push(ident.toChars()); - } - } - else if (level <= global.params.versionlevel || level <= mod.versionlevel) - inc = 1; - if (!definedInModule && - (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert))) - { - printDepsConditional(sc, this, "depsVersion "); - } - } - return (inc == 1); - } - - override void accept(Visitor v) - { - v.visit(this); - } - - override const(char)* toChars() - { - return ident ? ident.toChars() : "version".ptr; - } -} - -/*********************************************************** - */ -extern (C++) final class StaticIfCondition : Condition -{ - Expression exp; - int nest; // limit circular dependencies - - extern (D) this(Loc loc, Expression exp) - { - super(loc); - this.exp = exp; - } - - override Condition syntaxCopy() - { - return new StaticIfCondition(loc, exp.syntaxCopy()); - } - - override int include(Scope* sc, ScopeDsymbol sds) - { - version (none) - { - printf("StaticIfCondition::include(sc = %p, sds = %p) this=%p inc = %d\n", sc, sds, this, inc); - if (sds) - { - printf("\ts = '%s', kind = %s\n", sds.toChars(), sds.kind()); - } - } - - int errorReturn() - { - if (!global.gag) - inc = 2; // so we don't see the error message again - return 0; - } - - if (inc == 0) - { - if (exp.op == TOKerror || nest > 100) - { - error(loc, (nest > 1000) ? "unresolvable circular static if expression" : "error evaluating static if expression"); - return errorReturn(); - } - if (!sc) - { - error(loc, "static if conditional cannot be at global scope"); - inc = 2; - return 0; - } - - ++nest; - sc = sc.push(sc.scopesym); - sc.sds = sds; // sds gets any addMember() - - import ddmd.staticcond; - bool errors; - bool result = evalStaticCondition(sc, exp, exp, errors); - sc.pop(); - --nest; - // Prevent repeated condition evaluation. - // See: fail_compilation/fail7815.d - if (inc != 0) - return (inc == 1); - if (errors) - return errorReturn(); - if (result) - inc = 1; - else - inc = 2; - } - return (inc == 1); - } - - override void accept(Visitor v) - { - v.visit(this); - } - - override const(char)* toChars() - { - return exp ? exp.toChars() : "static if".ptr; - } -} - -extern (C++) int findCondition(Strings* ids, Identifier ident) -{ - if (ids) - { - for (size_t i = 0; i < ids.dim; i++) - { - const(char)* id = (*ids)[i]; - if (strcmp(id, ident.toChars()) == 0) - return true; - } - } - return false; -} - -// Helper for printing dependency information -private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[] depType) -{ - if (!global.params.moduleDeps || global.params.moduleDepsFile) - return; - OutBuffer* ob = global.params.moduleDeps; - Module imod = sc ? sc.instantiatingModule() : condition.mod; - if (!imod) - return; - ob.writestring(depType); - ob.writestring(imod.toPrettyChars()); - ob.writestring(" ("); - escapePath(ob, imod.srcfile.toChars()); - ob.writestring(") : "); - if (condition.ident) - ob.printf("%s\n", condition.ident.toChars()); - else - ob.printf("%d\n", condition.level); -} diff -Nru ldc-1.6.0/ddmd/cond.h ldc-1.8.0/ddmd/cond.h --- ldc-1.6.0/ddmd/cond.h 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/cond.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (c) 1999-2016 by Digital Mars - * All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/dlang/dmd/blob/master/src/cond.h - */ - -#ifndef DMD_DEBCOND_H -#define DMD_DEBCOND_H - -#include "globals.h" -#include "visitor.h" - -class Expression; -class Identifier; -struct OutBuffer; -class Module; -struct Scope; -class ScopeDsymbol; -class DebugCondition; -class ForeachStatement; -class ForeachRangeStatement; - -int findCondition(Strings *ids, Identifier *ident); - -class Condition -{ -public: - Loc loc; - // 0: not computed yet - // 1: include - // 2: do not include - int inc; - - virtual Condition *syntaxCopy() = 0; - virtual int include(Scope *sc, ScopeDsymbol *sds) = 0; - virtual DebugCondition *isDebugCondition() { return NULL; } - virtual void accept(Visitor *v) { v->visit(this); } -}; - -class StaticForeach -{ -public: - Loc loc; - - ForeachStatement *aggrfe; - ForeachRangeStatement *rangefe; - - bool needExpansion; - - StaticForeach *syntaxCopy(); -}; - -class DVCondition : public Condition -{ -public: - unsigned level; - Identifier *ident; - Module *mod; - - Condition *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } -}; - -class DebugCondition : public DVCondition -{ -public: - static void setGlobalLevel(unsigned level); - static void addGlobalIdent(const char *ident); - - int include(Scope *sc, ScopeDsymbol *sds); - DebugCondition *isDebugCondition() { return this; } - void accept(Visitor *v) { v->visit(this); } -}; - -class VersionCondition : public DVCondition -{ -public: - static void setGlobalLevel(unsigned level); - static void addGlobalIdent(const char *ident); - static void addPredefinedGlobalIdent(const char *ident); - - int include(Scope *sc, ScopeDsymbol *sds); - void accept(Visitor *v) { v->visit(this); } -}; - -class StaticIfCondition : public Condition -{ -public: - Expression *exp; - int nest; // limit circular dependencies - - Condition *syntaxCopy(); - int include(Scope *sc, ScopeDsymbol *sds); - void accept(Visitor *v) { v->visit(this); } -}; - -#endif diff -Nru ldc-1.6.0/ddmd/console.d ldc-1.8.0/ddmd/console.d --- ldc-1.6.0/ddmd/console.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/console.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,223 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/console.d, _console.d) - */ - -/******************************************** - * Control the various text mode attributes, such as color, when writing text - * to the console. - */ - -module ddmd.console; - -// Online documentation: https://dlang.org/phobos/ddmd_console.html - -import core.stdc.stdio; -extern (C) int isatty(int); - - -enum Color : int -{ - black = 0, - red = 1, - green = 2, - blue = 4, - yellow = red | green, - magenta = red | blue, - cyan = green | blue, - lightGray = red | green | blue, - bright = 8, - darkGray = bright | black, - brightRed = bright | red, - brightGreen = bright | green, - brightBlue = bright | blue, - brightYellow = bright | yellow, - brightMagenta = bright | magenta, - brightCyan = bright | cyan, - white = bright | lightGray, -} - -struct Console -{ - version (Windows) - { - import core.sys.windows.windows; - - private: - CONSOLE_SCREEN_BUFFER_INFO sbi; - HANDLE handle; - FILE* _fp; - - public: - - @property FILE* fp() { return _fp; } - - /********************************* - * Create an instance of Console connected to stream fp. - * Params: - * fp = io stream - * Returns: - * pointer to created Console - * null if failed - */ - static Console* create(FILE* fp) - { - /* Determine if stream fp is a console - */ - version (CRuntime_DigitalMars) - { - if (!isatty(fp._file)) - return null; - } - else version (CRuntime_Microsoft) - { - if (!isatty(fileno(fp))) - return null; - } - else - { - return null; - } - - DWORD nStdHandle; - if (fp == stdout) - nStdHandle = STD_OUTPUT_HANDLE; - else if (fp == stderr) - nStdHandle = STD_ERROR_HANDLE; - else - return null; - - auto h = GetStdHandle(nStdHandle); - CONSOLE_SCREEN_BUFFER_INFO sbi; - if (GetConsoleScreenBufferInfo(h, &sbi) == 0) // get initial state of console - return null; - - auto c = new Console(); - c._fp = fp; - c.handle = h; - c.sbi = sbi; - return c; - } - - /******************* - * Turn on/off intensity. - * Params: - * bright = turn it on - */ - void setColorBright(bool bright) - { - SetConsoleTextAttribute(handle, sbi.wAttributes | (bright ? FOREGROUND_INTENSITY : 0)); - } - - /*************************** - * Set color and intensity. - * Params: - * color = the color - */ - void setColor(Color color) - { - enum FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - WORD attr = sbi.wAttributes; - attr = (attr & ~(FOREGROUND_WHITE | FOREGROUND_INTENSITY)) | - ((color & Color.red) ? FOREGROUND_RED : 0) | - ((color & Color.green) ? FOREGROUND_GREEN : 0) | - ((color & Color.blue) ? FOREGROUND_BLUE : 0) | - ((color & Color.bright) ? FOREGROUND_INTENSITY : 0); - SetConsoleTextAttribute(handle, attr); - } - - /****************** - * Reset console attributes to what they were - * when create() was called. - */ - void resetColor() - { - SetConsoleTextAttribute(handle, sbi.wAttributes); - } - } - else version (Posix) - { - /* The ANSI escape codes are used. - * https://en.wikipedia.org/wiki/ANSI_escape_code - * Foreground colors: 30..37 - * Background colors: 40..47 - * Attributes: - * 0: reset all attributes - * 1: high intensity - * 2: low intensity - * 3: italic - * 4: single line underscore - * 5: slow blink - * 6: fast blink - * 7: reverse video - * 8: hidden - */ - - import core.sys.posix.unistd; - - private: - FILE* _fp; - - public: - - @property FILE* fp() { return _fp; } - - static Console* create(FILE* fp) - { - import core.stdc.stdlib : getenv; - const(char)* term = getenv("TERM"); - import core.stdc.string : strcmp; - if (!(isatty(STDERR_FILENO) && term && term[0] && 0 != strcmp(term, "dumb"))) - return null; - - auto c = new Console(); - c._fp = fp; - return c; - } - - void setColorBright(bool bright) - { - fprintf(_fp, "\033[%dm", bright); - } - - void setColor(Color color) - { - fprintf(_fp, "\033[%d;%dm", color & Color.bright ? 1 : 0, 30 + (color & ~Color.bright)); - } - - void resetColor() - { - fputs("\033[m", _fp); - } - } - else - { - @property FILE* fp() { assert(0); } - - static Console* create(FILE* fp) - { - return null; - } - - void setColorBright(bool bright) - { - assert(0); - } - - void setColor(Color color) - { - assert(0); - } - - void resetColor() - { - assert(0); - } - } - -} diff -Nru ldc-1.6.0/ddmd/constfold.d ldc-1.8.0/ddmd/constfold.d --- ldc-1.6.0/ddmd/constfold.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/constfold.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,1793 +0,0 @@ -/** - * Compiler implementation of the - * $(LINK2 http://www.dlang.org, D programming language). - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/constfold.d, _constfold.d) - */ - -module ddmd.constfold; - -// Online documentation: https://dlang.org/phobos/ddmd_constfold.html - -import core.stdc.string; -import core.stdc.stdio; -import ddmd.arraytypes; -import ddmd.complex; -import ddmd.ctfeexpr; -import ddmd.declaration; -import ddmd.dstruct; -import ddmd.errors; -import ddmd.expression; -import ddmd.globals; -import ddmd.mtype; -import ddmd.root.ctfloat; -import ddmd.root.port; -import ddmd.root.rmem; -import ddmd.sideeffect; -import ddmd.target; -import ddmd.tokens; -import ddmd.utf; - -version(IN_LLVM) -{ - import gen.dpragma; -} - -private enum LOG = false; - -extern (C++) Expression expType(Type type, Expression e) -{ - if (type != e.type) - { - e = e.copy(); - e.type = type; - } - return e; -} - -/* ================================== isConst() ============================== */ -extern (C++) int isConst(Expression e) -{ - //printf("Expression::isConst(): %s\n", e.toChars()); - switch (e.op) - { - case TOKint64: - case TOKfloat64: - case TOKcomplex80: - return 1; - case TOKnull: - return 0; - case TOKsymoff: -version(IN_LLVM) -{ - // We don't statically know anything about the address of a weak symbol - // if there is no offset. With an offset, we can at least say that it is - // non-zero. - SymOffExp soe = cast(SymOffExp) e; - if (soe.var.llvmInternal == LDCPragma.LLVMextern_weak && !soe.offset) - { - return 0; - } -} - return 2; - default: - return 0; - } - assert(0); -} - -/* =============================== constFold() ============================== */ -/* The constFold() functions were redundant with the optimize() ones, - * and so have been folded in with them. - */ -/* ========================================================================== */ -extern (C++) UnionExp Neg(Type type, Expression e1) -{ - UnionExp ue; - Loc loc = e1.loc; - if (e1.type.isreal()) - { - emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type); - } - else if (e1.type.isimaginary()) - { - emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type); - } - else if (e1.type.iscomplex()) - { - emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type); - } - else - { - emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type); - } - return ue; -} - -extern (C++) UnionExp Com(Type type, Expression e1) -{ - UnionExp ue; - Loc loc = e1.loc; - emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type); - return ue; -} - -extern (C++) UnionExp Not(Type type, Expression e1) -{ - UnionExp ue; - Loc loc = e1.loc; - emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(false) ? 1 : 0, type); - return ue; -} - -extern (C++) UnionExp Bool(Type type, Expression e1) -{ - UnionExp ue; - Loc loc = e1.loc; - emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(true) ? 1 : 0, type); - return ue; -} - -extern (C++) UnionExp Add(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - static if (LOG) - { - printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); - } - if (type.isreal()) - { - emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type); - } - else if (type.isimaginary()) - { - emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type); - } - else if (type.iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - auto c1 = complex_t(CTFloat.zero); - real_t r1 = 0; - real_t i1 = 0; - auto c2 = complex_t(CTFloat.zero); - real_t r2 = 0; - real_t i2 = 0; - auto v = complex_t(CTFloat.zero); - int x; - if (e1.type.isreal()) - { - r1 = e1.toReal(); - x = 0; - } - else if (e1.type.isimaginary()) - { - i1 = e1.toImaginary(); - x = 3; - } - else - { - c1 = e1.toComplex(); - x = 6; - } - if (e2.type.isreal()) - { - r2 = e2.toReal(); - } - else if (e2.type.isimaginary()) - { - i2 = e2.toImaginary(); - x += 1; - } - else - { - c2 = e2.toComplex(); - x += 2; - } - switch (x) - { - case 0 + 0: - v = complex_t(r1 + r2); - break; - case 0 + 1: - v = complex_t(r1, i2); - break; - case 0 + 2: - v = complex_t(r1 + creall(c2), cimagl(c2)); - break; - case 3 + 0: - v = complex_t(r2, i1); - break; - case 3 + 1: - v = complex_t(CTFloat.zero, i1 + i2); - break; - case 3 + 2: - v = complex_t(creall(c2), i1 + cimagl(c2)); - break; - case 6 + 0: - v = complex_t(creall(c1) + r2, cimagl(c2)); - break; - case 6 + 1: - v = complex_t(creall(c1), cimagl(c1) + i2); - break; - case 6 + 2: - v = c1 + c2; - break; - default: - assert(0); - } - emplaceExp!(ComplexExp)(&ue, loc, v, type); - } - else if (e1.op == TOKsymoff) - { - SymOffExp soe = cast(SymOffExp)e1; - emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger()); - ue.exp().type = type; - } - else if (e2.op == TOKsymoff) - { - SymOffExp soe = cast(SymOffExp)e2; - emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger()); - ue.exp().type = type; - } - else - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type); - return ue; -} - -extern (C++) UnionExp Min(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - if (type.isreal()) - { - emplaceExp!(RealExp)(&ue, loc, e1.toReal() - e2.toReal(), type); - } - else if (type.isimaginary()) - { - emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() - e2.toImaginary(), type); - } - else if (type.iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - auto c1 = complex_t(CTFloat.zero); - real_t r1 = 0; - real_t i1 = 0; - auto c2 = complex_t(CTFloat.zero); - real_t r2 = 0; - real_t i2 = 0; - auto v = complex_t(CTFloat.zero); - int x; - if (e1.type.isreal()) - { - r1 = e1.toReal(); - x = 0; - } - else if (e1.type.isimaginary()) - { - i1 = e1.toImaginary(); - x = 3; - } - else - { - c1 = e1.toComplex(); - x = 6; - } - if (e2.type.isreal()) - { - r2 = e2.toReal(); - } - else if (e2.type.isimaginary()) - { - i2 = e2.toImaginary(); - x += 1; - } - else - { - c2 = e2.toComplex(); - x += 2; - } - switch (x) - { - case 0 + 0: - v = complex_t(r1 - r2); - break; - case 0 + 1: - v = complex_t(r1, -i2); - break; - case 0 + 2: - v = complex_t(r1 - creall(c2), -cimagl(c2)); - break; - case 3 + 0: - v = complex_t(-r2, i1); - break; - case 3 + 1: - v = complex_t(CTFloat.zero, i1 - i2); - break; - case 3 + 2: - v = complex_t(-creall(c2), i1 - cimagl(c2)); - break; - case 6 + 0: - v = complex_t(creall(c1) - r2, cimagl(c1)); - break; - case 6 + 1: - v = complex_t(creall(c1), cimagl(c1) - i2); - break; - case 6 + 2: - v = c1 - c2; - break; - default: - assert(0); - } - emplaceExp!(ComplexExp)(&ue, loc, v, type); - } - else if (e1.op == TOKsymoff) - { - SymOffExp soe = cast(SymOffExp)e1; - emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger()); - ue.exp().type = type; - } - else - { - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() - e2.toInteger(), type); - } - return ue; -} - -extern (C++) UnionExp Mul(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - if (type.isfloating()) - { - auto c = complex_t(CTFloat.zero); - real_t r = 0; - if (e1.type.isreal()) - { - r = e1.toReal(); - c = e2.toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); - } - else if (e1.type.isimaginary()) - { - r = e1.toImaginary(); - c = e2.toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); - } - else if (e2.type.isreal()) - { - r = e2.toReal(); - c = e1.toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); - } - else if (e2.type.isimaginary()) - { - r = e2.toImaginary(); - c = e1.toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); - } - else - c = e1.toComplex() * e2.toComplex(); - if (type.isreal()) - emplaceExp!(RealExp)(&ue, loc, creall(c), type); - else if (type.isimaginary()) - emplaceExp!(RealExp)(&ue, loc, cimagl(c), type); - else if (type.iscomplex()) - emplaceExp!(ComplexExp)(&ue, loc, c, type); - else - assert(0); - } - else - { - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type); - } - return ue; -} - -extern (C++) UnionExp Div(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - if (type.isfloating()) - { - auto c = complex_t(CTFloat.zero); - //e1.type.print(); - //e2.type.print(); - if (e2.type.isreal()) - { - if (e1.type.isreal()) - { - version (all) - { - // Work around redundant REX.W prefix breaking Valgrind - // when built with affected versions of DMD. - // https://issues.dlang.org/show_bug.cgi?id=14952 - // This can be removed once compiling with DMD 2.068 or - // older is no longer supported. - const r1 = e1.toReal(); - const r2 = e2.toReal(); - emplaceExp!(RealExp)(&ue, loc, r1 / r2, type); - } - else - { - emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type); - } - return ue; - } - const r = e2.toReal(); - c = e1.toComplex(); - c = complex_t(creall(c) / r, cimagl(c) / r); - } - else if (e2.type.isimaginary()) - { - const r = e2.toImaginary(); - c = e1.toComplex(); - c = complex_t(cimagl(c) / r, -creall(c) / r); - } - else - { - c = e1.toComplex() / e2.toComplex(); - } - - if (type.isreal()) - emplaceExp!(RealExp)(&ue, loc, creall(c), type); - else if (type.isimaginary()) - emplaceExp!(RealExp)(&ue, loc, cimagl(c), type); - else if (type.iscomplex()) - emplaceExp!(ComplexExp)(&ue, loc, c, type); - else - assert(0); - } - else - { - sinteger_t n1; - sinteger_t n2; - sinteger_t n; - n1 = e1.toInteger(); - n2 = e2.toInteger(); - if (n2 == 0) - { - e2.error("divide by 0"); - emplaceExp!(ErrorExp)(&ue); - return ue; - } - if (n2 == -1 && !type.isunsigned()) - { - // Check for int.min / -1 - if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64) - { - e2.error("integer overflow: `int.min / -1`"); - emplaceExp!(ErrorExp)(&ue); - return ue; - } - else if (n1 == 0x8000000000000000L) // long.min / -1 - { - e2.error("integer overflow: `long.min / -1L`"); - emplaceExp!(ErrorExp)(&ue); - return ue; - } - } - if (e1.type.isunsigned() || e2.type.isunsigned()) - n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2); - else - n = n1 / n2; - emplaceExp!(IntegerExp)(&ue, loc, n, type); - } - return ue; -} - -extern (C++) UnionExp Mod(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - if (type.isfloating()) - { - auto c = complex_t(CTFloat.zero); - if (e2.type.isreal()) - { - const r2 = e2.toReal(); - c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2); - } - else if (e2.type.isimaginary()) - { - const i2 = e2.toImaginary(); - c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2); - } - else - assert(0); - if (type.isreal()) - emplaceExp!(RealExp)(&ue, loc, creall(c), type); - else if (type.isimaginary()) - emplaceExp!(RealExp)(&ue, loc, cimagl(c), type); - else if (type.iscomplex()) - emplaceExp!(ComplexExp)(&ue, loc, c, type); - else - assert(0); - } - else - { - sinteger_t n1; - sinteger_t n2; - sinteger_t n; - n1 = e1.toInteger(); - n2 = e2.toInteger(); - if (n2 == 0) - { - e2.error("divide by 0"); - emplaceExp!(ErrorExp)(&ue); - return ue; - } - if (n2 == -1 && !type.isunsigned()) - { - // Check for int.min % -1 - if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64) - { - e2.error("integer overflow: `int.min %% -1`"); - emplaceExp!(ErrorExp)(&ue); - return ue; - } - else if (n1 == 0x8000000000000000L) // long.min % -1 - { - e2.error("integer overflow: `long.min %% -1L`"); - emplaceExp!(ErrorExp)(&ue); - return ue; - } - } - if (e1.type.isunsigned() || e2.type.isunsigned()) - n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2); - else - n = n1 % n2; - emplaceExp!(IntegerExp)(&ue, loc, n, type); - } - return ue; -} - -extern (C++) UnionExp Pow(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - // Handle integer power operations. - if (e2.type.isintegral()) - { - dinteger_t n = e2.toInteger(); - bool neg; - if (!e2.type.isunsigned() && cast(sinteger_t)n < 0) - { - if (e1.type.isintegral()) - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; - } - // Don't worry about overflow, from now on n is unsigned. - neg = true; - n = -n; - } - else - neg = false; - UnionExp ur, uv; - if (e1.type.iscomplex()) - { - emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type); - emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type); - } - else if (e1.type.isfloating()) - { - emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type); - emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type); - } - else - { - emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type); - emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type); - } - Expression r = ur.exp(); - Expression v = uv.exp(); - while (n != 0) - { - if (n & 1) - { - // v = v * r; - uv = Mul(loc, v.type, v, r); - } - n >>= 1; - // r = r * r - ur = Mul(loc, r.type, r, r); - } - if (neg) - { - // ue = 1.0 / v - UnionExp one; - emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type); - uv = Div(loc, v.type, one.exp(), v); - } - if (type.iscomplex()) - emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type); - else if (type.isintegral()) - emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type); - else - emplaceExp!(RealExp)(&ue, loc, v.toReal(), type); - } - else if (e2.type.isfloating()) - { - // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN - if (e1.toReal() < CTFloat.zero) - { - emplaceExp!(RealExp)(&ue, loc, Target.RealProperties.nan, type); - } - else - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - } - else - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; -} - -extern (C++) UnionExp Shl(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type); - return ue; -} - -extern (C++) UnionExp Shr(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - dinteger_t value = e1.toInteger(); - dinteger_t dcount = e2.toInteger(); - assert(dcount <= 0xFFFFFFFF); - uint count = cast(uint)dcount; - switch (e1.type.toBasetype().ty) - { - case Tint8: - value = cast(d_int8)value >> count; - break; - case Tuns8: - case Tchar: - value = cast(d_uns8)value >> count; - break; - case Tint16: - value = cast(d_int16)value >> count; - break; - case Tuns16: - case Twchar: - value = cast(d_uns16)value >> count; - break; - case Tint32: - value = cast(d_int32)value >> count; - break; - case Tuns32: - case Tdchar: - value = cast(d_uns32)value >> count; - break; - case Tint64: - value = cast(d_int64)value >> count; - break; - case Tuns64: - value = cast(d_uns64)value >> count; - break; - case Terror: - emplaceExp!(ErrorExp)(&ue); - return ue; - default: - assert(0); - } - emplaceExp!(IntegerExp)(&ue, loc, value, type); - return ue; -} - -extern (C++) UnionExp Ushr(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - dinteger_t value = e1.toInteger(); - dinteger_t dcount = e2.toInteger(); - assert(dcount <= 0xFFFFFFFF); - uint count = cast(uint)dcount; - switch (e1.type.toBasetype().ty) - { - case Tint8: - case Tuns8: - case Tchar: - // Possible only with >>>=. >>> always gets promoted to int. - value = (value & 0xFF) >> count; - break; - case Tint16: - case Tuns16: - case Twchar: - // Possible only with >>>=. >>> always gets promoted to int. - value = (value & 0xFFFF) >> count; - break; - case Tint32: - case Tuns32: - case Tdchar: - value = (value & 0xFFFFFFFF) >> count; - break; - case Tint64: - case Tuns64: - value = cast(d_uns64)value >> count; - break; - case Terror: - emplaceExp!(ErrorExp)(&ue); - return ue; - default: - assert(0); - } - emplaceExp!(IntegerExp)(&ue, loc, value, type); - return ue; -} - -extern (C++) UnionExp And(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type); - return ue; -} - -extern (C++) UnionExp Or(Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type); - return ue; -} - -extern (C++) UnionExp Xor(Loc loc, Type type, Expression e1, Expression e2) -{ - //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars()); - UnionExp ue; - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type); - return ue; -} - -/* Also returns TOKcantexp if cannot be computed. - */ -extern (C++) UnionExp Equal(TOK op, Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - int cmp = 0; - real_t r1 = 0; - real_t r2 = 0; - //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); - assert(op == TOKequal || op == TOKnotequal); - if (e1.op == TOKnull) - { - if (e2.op == TOKnull) - cmp = 1; - else if (e2.op == TOKstring) - { - StringExp es2 = cast(StringExp)e2; - cmp = (0 == es2.len); - } - else if (e2.op == TOKarrayliteral) - { - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; - cmp = !es2.elements || (0 == es2.elements.dim); - } - else - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; - } - } - else if (e2.op == TOKnull) - { - if (e1.op == TOKstring) - { - StringExp es1 = cast(StringExp)e1; - cmp = (0 == es1.len); - } - else if (e1.op == TOKarrayliteral) - { - ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; - cmp = !es1.elements || (0 == es1.elements.dim); - } - else - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; - } - } - else if (e1.op == TOKstring && e2.op == TOKstring) - { - StringExp es1 = cast(StringExp)e1; - StringExp es2 = cast(StringExp)e2; - if (es1.sz != es2.sz) - { - assert(global.errors); - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; - } - if (es1.len == es2.len && memcmp(es1.string, es2.string, es1.sz * es1.len) == 0) - cmp = 1; - else - cmp = 0; - } - else if (e1.op == TOKarrayliteral && e2.op == TOKarrayliteral) - { - ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; - if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) - cmp = 1; // both arrays are empty - else if (!es1.elements || !es2.elements) - cmp = 0; - else if (es1.elements.dim != es2.elements.dim) - cmp = 0; - else - { - for (size_t i = 0; i < es1.elements.dim; i++) - { - auto ee1 = es1.getElement(i); - auto ee2 = es2.getElement(i); - ue = Equal(TOKequal, loc, Type.tint32, ee1, ee2); - if (CTFEExp.isCantExp(ue.exp())) - return ue; - cmp = cast(int)ue.exp().toInteger(); - if (cmp == 0) - break; - } - } - } - else if (e1.op == TOKarrayliteral && e2.op == TOKstring) - { - // Swap operands and use common code - Expression etmp = e1; - e1 = e2; - e2 = etmp; - goto Lsa; - } - else if (e1.op == TOKstring && e2.op == TOKarrayliteral) - { - Lsa: - StringExp es1 = cast(StringExp)e1; - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; - size_t dim1 = es1.len; - size_t dim2 = es2.elements ? es2.elements.dim : 0; - if (dim1 != dim2) - cmp = 0; - else - { - cmp = 1; // if dim1 winds up being 0 - for (size_t i = 0; i < dim1; i++) - { - uinteger_t c = es1.charAt(i); - auto ee2 = es2.getElement(i); - if (ee2.isConst() != 1) - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; - } - cmp = (c == ee2.toInteger()); - if (cmp == 0) - break; - } - } - } - else if (e1.op == TOKstructliteral && e2.op == TOKstructliteral) - { - StructLiteralExp es1 = cast(StructLiteralExp)e1; - StructLiteralExp es2 = cast(StructLiteralExp)e2; - if (es1.sd != es2.sd) - cmp = 0; - else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) - cmp = 1; // both arrays are empty - else if (!es1.elements || !es2.elements) - cmp = 0; - else if (es1.elements.dim != es2.elements.dim) - cmp = 0; - else - { - cmp = 1; - for (size_t i = 0; i < es1.elements.dim; i++) - { - Expression ee1 = (*es1.elements)[i]; - Expression ee2 = (*es2.elements)[i]; - if (ee1 == ee2) - continue; - if (!ee1 || !ee2) - { - cmp = 0; - break; - } - ue = Equal(TOKequal, loc, Type.tint32, ee1, ee2); - if (ue.exp().op == TOKcantexp) - return ue; - cmp = cast(int)ue.exp().toInteger(); - if (cmp == 0) - break; - } - } - } - else if (e1.isConst() != 1 || e2.isConst() != 1) - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; - } - else if (e1.type.isreal()) - { - r1 = e1.toReal(); - r2 = e2.toReal(); - goto L1; - } - else if (e1.type.isimaginary()) - { - r1 = e1.toImaginary(); - r2 = e2.toImaginary(); - L1: - if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered - { - cmp = 0; - } - else - { - cmp = (r1 == r2); - } - } - else if (e1.type.iscomplex()) - { - cmp = e1.toComplex() == e2.toComplex(); - } - else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer) - { - cmp = (e1.toInteger() == e2.toInteger()); - } - else - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; - } - if (op == TOKnotequal) - cmp ^= 1; - emplaceExp!(IntegerExp)(&ue, loc, cmp, type); - return ue; -} - -extern (C++) UnionExp Identity(TOK op, Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - int cmp; - if (e1.op == TOKnull) - { - cmp = (e2.op == TOKnull); - } - else if (e2.op == TOKnull) - { - cmp = 0; - } - else if (e1.op == TOKsymoff && e2.op == TOKsymoff) - { - SymOffExp es1 = cast(SymOffExp)e1; - SymOffExp es2 = cast(SymOffExp)e2; - cmp = (es1.var == es2.var && es1.offset == es2.offset); - } - else - { - if (e1.type.isreal()) - { - cmp = RealEquals(e1.toReal(), e2.toReal()); - } - else if (e1.type.isimaginary()) - { - cmp = RealEquals(e1.toImaginary(), e2.toImaginary()); - } - else if (e1.type.iscomplex()) - { - complex_t v1 = e1.toComplex(); - complex_t v2 = e2.toComplex(); - cmp = RealEquals(creall(v1), creall(v2)) && RealEquals(cimagl(v1), cimagl(v1)); - } - else - { - ue = Equal((op == TOKidentity) ? TOKequal : TOKnotequal, loc, type, e1, e2); - return ue; - } - } - if (op == TOKnotidentity) - cmp ^= 1; - emplaceExp!(IntegerExp)(&ue, loc, cmp, type); - return ue; -} - -extern (C++) UnionExp Cmp(TOK op, Loc loc, Type type, Expression e1, Expression e2) -{ - UnionExp ue; - dinteger_t n; - real_t r1 = 0; - real_t r2 = 0; - //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); - if (e1.op == TOKstring && e2.op == TOKstring) - { - StringExp es1 = cast(StringExp)e1; - StringExp es2 = cast(StringExp)e2; - size_t sz = es1.sz; - assert(sz == es2.sz); - size_t len = es1.len; - if (es2.len < len) - len = es2.len; - int rawCmp = memcmp(es1.string, es2.string, sz * len); - if (rawCmp == 0) - rawCmp = cast(int)(es1.len - es2.len); - n = specificCmp(op, rawCmp); - } - else if (e1.isConst() != 1 || e2.isConst() != 1) - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; - } - else if (e1.type.isreal()) - { - r1 = e1.toReal(); - r2 = e2.toReal(); - goto L1; - } - else if (e1.type.isimaginary()) - { - r1 = e1.toImaginary(); - r2 = e2.toImaginary(); - L1: - n = realCmp(op, r1, r2); - } - else if (e1.type.iscomplex()) - { - assert(0); - } - else - { - sinteger_t n1; - sinteger_t n2; - n1 = e1.toInteger(); - n2 = e2.toInteger(); - if (e1.type.isunsigned() || e2.type.isunsigned()) - n = intUnsignedCmp(op, n1, n2); - else - n = intSignedCmp(op, n1, n2); - } - emplaceExp!(IntegerExp)(&ue, loc, n, type); - return ue; -} - -/* Also returns TOKcantexp if cannot be computed. - * to: type to cast to - * type: type to paint the result - */ -extern (C++) UnionExp Cast(Loc loc, Type type, Type to, Expression e1) -{ - UnionExp ue; - Type tb = to.toBasetype(); - Type typeb = type.toBasetype(); - //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars()); - //printf("\te1.type = %s\n", e1.type.toChars()); - if (e1.type.equals(type) && type.equals(to)) - { - emplaceExp!(UnionExp)(&ue, e1); - return ue; - } - if (e1.op == TOKvector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to)) - { - Expression ex = (cast(VectorExp)e1).e1; - emplaceExp!(UnionExp)(&ue, ex); - return ue; - } - if (e1.type.implicitConvTo(to) >= MATCHconst || to.implicitConvTo(e1.type) >= MATCHconst) - { - goto L1; - } - // Allow covariant converions of delegates - // (Perhaps implicit conversion from pure to impure should be a MATCHconst, - // then we wouldn't need this extra check.) - if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCHconvert) - { - goto L1; - } - /* Allow casting from one string type to another - */ - if (e1.op == TOKstring) - { - if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size()) - { - goto L1; - } - } - if (e1.op == TOKarrayliteral && typeb == tb) - { - L1: - Expression ex = expType(to, e1); - emplaceExp!(UnionExp)(&ue, ex); - return ue; - } - if (e1.isConst() != 1) - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - } - else if (tb.ty == Tbool) - { - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() != 0, type); - } - else if (type.isintegral()) - { - if (e1.type.isfloating()) - { - dinteger_t result; - real_t r = e1.toReal(); - switch (typeb.ty) - { - case Tint8: - result = cast(d_int8)cast(sinteger_t)r; - break; - case Tchar: - case Tuns8: - result = cast(d_uns8)cast(dinteger_t)r; - break; - case Tint16: - result = cast(d_int16)cast(sinteger_t)r; - break; - case Twchar: - case Tuns16: - result = cast(d_uns16)cast(dinteger_t)r; - break; - case Tint32: - result = cast(d_int32)r; - break; - case Tdchar: - case Tuns32: - result = cast(d_uns32)r; - break; - case Tint64: - result = cast(d_int64)r; - break; - case Tuns64: - result = cast(d_uns64)r; - break; - default: - assert(0); - } - emplaceExp!(IntegerExp)(&ue, loc, result, type); - } - else if (type.isunsigned()) - emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type); - else - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type); - } - else if (tb.isreal()) - { - real_t value = e1.toReal(); - emplaceExp!(RealExp)(&ue, loc, value, type); - } - else if (tb.isimaginary()) - { - real_t value = e1.toImaginary(); - emplaceExp!(RealExp)(&ue, loc, value, type); - } - else if (tb.iscomplex()) - { - complex_t value = e1.toComplex(); - emplaceExp!(ComplexExp)(&ue, loc, value, type); - } - else if (tb.isscalar()) - { - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type); - } - else if (tb.ty == Tvoid) - { - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - } - else if (tb.ty == Tstruct && e1.op == TOKint64) - { - // Struct = 0; - StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration(); - assert(sd); - auto elements = new Expressions(); - for (size_t i = 0; i < sd.fields.dim; i++) - { - VarDeclaration v = sd.fields[i]; - UnionExp zero; - emplaceExp!(IntegerExp)(&zero, 0); - ue = Cast(loc, v.type, v.type, zero.exp()); - if (ue.exp().op == TOKcantexp) - return ue; - elements.push(ue.exp().copy()); - } - emplaceExp!(StructLiteralExp)(&ue, loc, sd, elements); - ue.exp().type = type; - } - else - { - if (type != Type.terror) - { - // have to change to Internal Compiler Error - // all invalid casts should be handled already in Expression::castTo(). - error(loc, "cannot cast `%s` to `%s`", e1.type.toChars(), type.toChars()); - } - emplaceExp!(ErrorExp)(&ue); - } - return ue; -} - -extern (C++) UnionExp ArrayLength(Type type, Expression e1) -{ - UnionExp ue; - Loc loc = e1.loc; - if (e1.op == TOKstring) - { - StringExp es1 = cast(StringExp)e1; - emplaceExp!(IntegerExp)(&ue, loc, es1.len, type); - } - else if (e1.op == TOKarrayliteral) - { - ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; - size_t dim = ale.elements ? ale.elements.dim : 0; - emplaceExp!(IntegerExp)(&ue, loc, dim, type); - } - else if (e1.op == TOKassocarrayliteral) - { - AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1; - size_t dim = ale.keys.dim; - emplaceExp!(IntegerExp)(&ue, loc, dim, type); - } - else if (e1.type.toBasetype().ty == Tsarray) - { - Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim; - emplaceExp!(UnionExp)(&ue, e); - } - else - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; -} - -/* Also return TOKcantexp if this fails - */ -extern (C++) UnionExp Index(Type type, Expression e1, Expression e2) -{ - UnionExp ue; - Loc loc = e1.loc; - //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); - assert(e1.type); - if (e1.op == TOKstring && e2.op == TOKint64) - { - StringExp es1 = cast(StringExp)e1; - uinteger_t i = e2.toInteger(); - if (i >= es1.len) - { - e1.error("string index %llu is out of bounds `[0 .. %llu]`", i, cast(ulong)es1.len); - emplaceExp!(ErrorExp)(&ue); - } - else - { - emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type); - } - } - else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOKint64) - { - TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype(); - uinteger_t length = tsa.dim.toInteger(); - uinteger_t i = e2.toInteger(); - if (i >= length) - { - e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length); - emplaceExp!(ErrorExp)(&ue); - } - else if (e1.op == TOKarrayliteral) - { - ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; - auto e = ale.getElement(cast(size_t)i); - e.type = type; - e.loc = loc; - if (hasSideEffect(e)) - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - else - emplaceExp!(UnionExp)(&ue, e); - } - else - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - } - else if (e1.type.toBasetype().ty == Tarray && e2.op == TOKint64) - { - uinteger_t i = e2.toInteger(); - if (e1.op == TOKarrayliteral) - { - ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; - if (i >= ale.elements.dim) - { - e1.error("array index %llu is out of bounds `%s[0 .. %u]`", i, e1.toChars(), ale.elements.dim); - emplaceExp!(ErrorExp)(&ue); - } - else - { - auto e = ale.getElement(cast(size_t)i); - e.type = type; - e.loc = loc; - if (hasSideEffect(e)) - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - else - emplaceExp!(UnionExp)(&ue, e); - } - } - else - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - } - else if (e1.op == TOKassocarrayliteral) - { - AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1; - /* Search the keys backwards, in case there are duplicate keys - */ - for (size_t i = ae.keys.dim; i;) - { - i--; - Expression ekey = (*ae.keys)[i]; - ue = Equal(TOKequal, loc, Type.tbool, ekey, e2); - if (CTFEExp.isCantExp(ue.exp())) - return ue; - if (ue.exp().isBool(true)) - { - Expression e = (*ae.values)[i]; - e.type = type; - e.loc = loc; - if (hasSideEffect(e)) - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - else - emplaceExp!(UnionExp)(&ue, e); - return ue; - } - } - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - } - else - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; -} - -/* Also return TOKcantexp if this fails - */ -extern (C++) UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) -{ - UnionExp ue; - Loc loc = e1.loc; - static if (LOG) - { - printf("Slice()\n"); - if (lwr) - { - printf("\te1 = %s\n", e1.toChars()); - printf("\tlwr = %s\n", lwr.toChars()); - printf("\tupr = %s\n", upr.toChars()); - } - } - if (e1.op == TOKstring && lwr.op == TOKint64 && upr.op == TOKint64) - { - StringExp es1 = cast(StringExp)e1; - uinteger_t ilwr = lwr.toInteger(); - uinteger_t iupr = upr.toInteger(); - if (iupr > es1.len || ilwr > iupr) - { - e1.error("string slice `[%llu .. %llu]` is out of bounds", ilwr, iupr); - emplaceExp!(ErrorExp)(&ue); - } - else - { - size_t len = cast(size_t)(iupr - ilwr); - ubyte sz = es1.sz; - void* s = mem.xmalloc(len * sz); - memcpy(cast(char*)s, es1.string + ilwr * sz, len * sz); - emplaceExp!(StringExp)(&ue, loc, s, len, es1.postfix); - StringExp es = cast(StringExp)ue.exp(); - es.sz = sz; - es.committed = es1.committed; - es.type = type; - } - } - else if (e1.op == TOKarrayliteral && lwr.op == TOKint64 && upr.op == TOKint64 && !hasSideEffect(e1)) - { - ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; - uinteger_t ilwr = lwr.toInteger(); - uinteger_t iupr = upr.toInteger(); - if (iupr > es1.elements.dim || ilwr > iupr) - { - e1.error("array slice `[%llu .. %llu]` is out of bounds", ilwr, iupr); - emplaceExp!(ErrorExp)(&ue); - } - else - { - auto elements = new Expressions(); - elements.setDim(cast(size_t)(iupr - ilwr)); - memcpy(elements.tdata(), es1.elements.tdata() + ilwr, cast(size_t)(iupr - ilwr) * ((*es1.elements)[0]).sizeof); - emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elements); - ue.exp().type = type; - } - } - else - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - assert(ue.exp().type); - return ue; -} - -/* Set a slice of char/integer array literal 'existingAE' from a string 'newval'. - * existingAE[firstIndex..firstIndex+newval.length] = newval. - */ -extern (C++) void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex) -{ - const len = newval.len; - Type elemType = existingAE.type.nextOf(); - foreach (j; 0 .. len) - { - const val = newval.getCodeUnit(j); - (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType); - } -} - -/* Set a slice of string 'existingSE' from a char array literal 'newae'. - * existingSE[firstIndex..firstIndex+newae.length] = newae. - */ -extern (C++) void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex) -{ - assert(existingSE.ownedByCtfe != OWNEDcode); - foreach (j; 0 .. newae.elements.dim) - { - existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae.getElement(j).toInteger()); - } -} - -/* Set a slice of string 'existingSE' from a string 'newstr'. - * existingSE[firstIndex..firstIndex+newstr.length] = newstr. - */ -extern (C++) void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex) -{ - assert(existingSE.ownedByCtfe != OWNEDcode); - size_t sz = existingSE.sz; - assert(sz == newstr.sz); - memcpy(existingSE.string + firstIndex * sz, newstr.string, sz * newstr.len); -} - -/* Compare a string slice with another string slice. - * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len]) - */ -extern (C++) int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len) -{ - size_t sz = se1.sz; - assert(sz == se2.sz); - return memcmp(se1.string + sz * lo1, se2.string + sz * lo2, sz * len); -} - -/* Compare a string slice with an array literal slice - * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len]) - */ -extern (C++) int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len) -{ - foreach (j; 0 .. len) - { - const val2 = cast(dchar)ae2.getElement(j + lo2).toInteger(); - const val1 = se1.getCodeUnit(j + lo1); - const int c = val1 - val2; - if (c) - return c; - } - return 0; -} - -/* Also return TOKcantexp if this fails - */ -extern (C++) UnionExp Cat(Type type, Expression e1, Expression e2) -{ - UnionExp ue; - Expression e = CTFEExp.cantexp; - Loc loc = e1.loc; - Type t; - Type t1 = e1.type.toBasetype(); - Type t2 = e2.type.toBasetype(); - //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); - //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars()); - if (e1.op == TOKnull && (e2.op == TOKint64 || e2.op == TOKstructliteral)) - { - e = e2; - t = t1; - goto L2; - } - else if ((e1.op == TOKint64 || e1.op == TOKstructliteral) && e2.op == TOKnull) - { - e = e1; - t = t2; - L2: - Type tn = e.type.toBasetype(); - if (tn.ty == Tchar || tn.ty == Twchar || tn.ty == Tdchar) - { - // Create a StringExp - if (t.nextOf()) - t = t.nextOf().toBasetype(); - ubyte sz = cast(ubyte)t.size(); - dinteger_t v = e.toInteger(); - size_t len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v); - void* s = mem.xmalloc(len * sz); - if (t.ty == tn.ty) - Port.valcpy(s, v, sz); - else - utf_encode(sz, s, cast(dchar)v); - emplaceExp!(StringExp)(&ue, loc, s, len); - StringExp es = cast(StringExp)ue.exp(); - es.sz = sz; - es.committed = 1; - } - else - { - // Create an ArrayLiteralExp - auto elements = new Expressions(); - elements.push(e); - emplaceExp!(ArrayLiteralExp)(&ue, e.loc, elements); - } - ue.exp().type = type; - assert(ue.exp().type); - return ue; - } - else if (e1.op == TOKnull && e2.op == TOKnull) - { - if (type == e1.type) - { - // Handle null ~= null - if (t1.ty == Tarray && t2 == t1.nextOf()) - { - emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, e2); - ue.exp().type = type; - assert(ue.exp().type); - return ue; - } - else - { - emplaceExp!(UnionExp)(&ue, e1); - assert(ue.exp().type); - return ue; - } - } - if (type == e2.type) - { - emplaceExp!(UnionExp)(&ue, e2); - assert(ue.exp().type); - return ue; - } - emplaceExp!(NullExp)(&ue, e1.loc, type); - assert(ue.exp().type); - return ue; - } - else if (e1.op == TOKstring && e2.op == TOKstring) - { - // Concatenate the strings - StringExp es1 = cast(StringExp)e1; - StringExp es2 = cast(StringExp)e2; - size_t len = es1.len + es2.len; - ubyte sz = es1.sz; - if (sz != es2.sz) - { - /* Can happen with: - * auto s = "foo"d ~ "bar"c; - */ - assert(global.errors); - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - assert(ue.exp().type); - return ue; - } - void* s = mem.xmalloc(len * sz); - memcpy(cast(char*)s, es1.string, es1.len * sz); - memcpy(cast(char*)s + es1.len * sz, es2.string, es2.len * sz); - emplaceExp!(StringExp)(&ue, loc, s, len); - StringExp es = cast(StringExp)ue.exp(); - es.sz = sz; - es.committed = es1.committed | es2.committed; - es.type = type; - assert(ue.exp().type); - return ue; - } - else if (e2.op == TOKstring && e1.op == TOKarrayliteral && t1.nextOf().isintegral()) - { - // [chars] ~ string --> [chars] - StringExp es = cast(StringExp)e2; - ArrayLiteralExp ea = cast(ArrayLiteralExp)e1; - size_t len = es.len + ea.elements.dim; - auto elems = new Expressions(); - elems.setDim(len); - for (size_t i = 0; i < ea.elements.dim; ++i) - { - (*elems)[i] = ea.getElement(i); - } - emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elems); - ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp(); - dest.type = type; - sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim); - assert(ue.exp().type); - return ue; - } - else if (e1.op == TOKstring && e2.op == TOKarrayliteral && t2.nextOf().isintegral()) - { - // string ~ [chars] --> [chars] - StringExp es = cast(StringExp)e1; - ArrayLiteralExp ea = cast(ArrayLiteralExp)e2; - size_t len = es.len + ea.elements.dim; - auto elems = new Expressions(); - elems.setDim(len); - for (size_t i = 0; i < ea.elements.dim; ++i) - { - (*elems)[es.len + i] = ea.getElement(i); - } - emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elems); - ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp(); - dest.type = type; - sliceAssignArrayLiteralFromString(dest, es, 0); - assert(ue.exp().type); - return ue; - } - else if (e1.op == TOKstring && e2.op == TOKint64) - { - // string ~ char --> string - StringExp es1 = cast(StringExp)e1; - StringExp es; - ubyte sz = es1.sz; - dinteger_t v = e2.toInteger(); - // Is it a concatenation of homogenous types? - // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar) - bool homoConcat = (sz == t2.size()); - size_t len = es1.len; - len += homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v); - void* s = mem.xmalloc(len * sz); - memcpy(s, es1.string, es1.len * sz); - if (homoConcat) - Port.valcpy(cast(char*)s + (sz * es1.len), v, sz); - else - utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v); - emplaceExp!(StringExp)(&ue, loc, s, len); - es = cast(StringExp)ue.exp(); - es.sz = sz; - es.committed = es1.committed; - es.type = type; - assert(ue.exp().type); - return ue; - } - else if (e1.op == TOKint64 && e2.op == TOKstring) - { - // Concatenate the strings - StringExp es2 = cast(StringExp)e2; - size_t len = 1 + es2.len; - ubyte sz = es2.sz; - dinteger_t v = e1.toInteger(); - void* s = mem.xmalloc(len * sz); - memcpy(cast(char*)s, &v, sz); - memcpy(cast(char*)s + sz, es2.string, es2.len * sz); - emplaceExp!(StringExp)(&ue, loc, s, len); - StringExp es = cast(StringExp)ue.exp(); - es.sz = sz; - es.committed = es2.committed; - es.type = type; - assert(ue.exp().type); - return ue; - } - else if (e1.op == TOKarrayliteral && e2.op == TOKarrayliteral && t1.nextOf().equals(t2.nextOf())) - { - // Concatenate the arrays - auto elems = ArrayLiteralExp.copyElements(e1, e2); - - emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elems); - - e = ue.exp(); - if (type.toBasetype().ty == Tsarray) - { - e.type = t1.nextOf().sarrayOf(elems.dim); - } - else - e.type = type; - assert(ue.exp().type); - return ue; - } - else if (e1.op == TOKarrayliteral && e2.op == TOKnull && t1.nextOf().equals(t2.nextOf())) - { - e = e1; - goto L3; - } - else if (e1.op == TOKnull && e2.op == TOKarrayliteral && t1.nextOf().equals(t2.nextOf())) - { - e = e2; - L3: - // Concatenate the array with null - auto elems = ArrayLiteralExp.copyElements(e); - - emplaceExp!(ArrayLiteralExp)(&ue, e.loc, elems); - - e = ue.exp(); - if (type.toBasetype().ty == Tsarray) - { - e.type = t1.nextOf().sarrayOf(elems.dim); - } - else - e.type = type; - assert(ue.exp().type); - return ue; - } - else if ((e1.op == TOKarrayliteral || e1.op == TOKnull) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type)) - { - auto elems = (e1.op == TOKarrayliteral) - ? ArrayLiteralExp.copyElements(e1) : new Expressions(); - elems.push(e2); - - emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elems); - - e = ue.exp(); - if (type.toBasetype().ty == Tsarray) - { - e.type = e2.type.sarrayOf(elems.dim); - } - else - e.type = type; - assert(ue.exp().type); - return ue; - } - else if (e2.op == TOKarrayliteral && e2.type.toBasetype().nextOf().equals(e1.type)) - { - auto elems = ArrayLiteralExp.copyElements(e1, e2); - - emplaceExp!(ArrayLiteralExp)(&ue, e2.loc, elems); - - e = ue.exp(); - if (type.toBasetype().ty == Tsarray) - { - e.type = e1.type.sarrayOf(elems.dim); - } - else - e.type = type; - assert(ue.exp().type); - return ue; - } - else if (e1.op == TOKnull && e2.op == TOKstring) - { - t = e1.type; - e = e2; - goto L1; - } - else if (e1.op == TOKstring && e2.op == TOKnull) - { - e = e1; - t = e2.type; - L1: - Type tb = t.toBasetype(); - if (tb.ty == Tarray && tb.nextOf().equivalent(e.type)) - { - auto expressions = new Expressions(); - expressions.push(e); - emplaceExp!(ArrayLiteralExp)(&ue, loc, expressions); - e = ue.exp(); - e.type = t; - } - else - { - emplaceExp!(UnionExp)(&ue, e); - e = ue.exp(); - } - if (!e.type.equals(type)) - { - StringExp se = cast(StringExp)e.copy(); - e = se.castTo(null, type); - emplaceExp!(UnionExp)(&ue, e); - e = ue.exp(); - } - } - else - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - assert(ue.exp().type); - return ue; -} - -extern (C++) UnionExp Ptr(Type type, Expression e1) -{ - //printf("Ptr(e1 = %s)\n", e1.toChars()); - UnionExp ue; - if (e1.op == TOKadd) - { - AddExp ae = cast(AddExp)e1; - if (ae.e1.op == TOKaddress && ae.e2.op == TOKint64) - { - AddrExp ade = cast(AddrExp)ae.e1; - if (ade.e1.op == TOKstructliteral) - { - StructLiteralExp se = cast(StructLiteralExp)ade.e1; - uint offset = cast(uint)ae.e2.toInteger(); - Expression e = se.getField(type, offset); - if (e) - { - emplaceExp!(UnionExp)(&ue, e); - return ue; - } - } - } - } - emplaceExp!(CTFEExp)(&ue, TOKcantexp); - return ue; -} diff -Nru ldc-1.6.0/ddmd/cppmangle.d ldc-1.8.0/ddmd/cppmangle.d --- ldc-1.6.0/ddmd/cppmangle.d 2018-01-03 19:40:43.000000000 +0000 +++ ldc-1.8.0/ddmd/cppmangle.d 1970-01-01 00:00:00.000000000 +0000 @@ -1,2001 +0,0 @@ -/** - * Compiler implementation of the $(LINK2 http://www.dlang.org, D programming language) - * - * Copyright: Copyright (c) 1999-2017 by Digital Mars, All Rights Reserved - * Authors: Walter Bright, http://www.digitalmars.com - * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/ddmd/cppmangle.d, _cppmangle.d) - */ - -module ddmd.cppmangle; - -// Online documentation: https://dlang.org/phobos/ddmd_cppmangle.html - -import core.stdc.string; -import core.stdc.stdio; - -import ddmd.arraytypes; -import ddmd.declaration; -import ddmd.dsymbol; -import ddmd.dtemplate; -import ddmd.errors; -import ddmd.expression; -import ddmd.func; -import ddmd.globals; -import ddmd.id; -import ddmd.mtype; -import ddmd.root.outbuffer; -import ddmd.root.rootobject; -import ddmd.target; -import ddmd.tokens; -import ddmd.visitor; - -/* Do mangling for C++ linkage. - * No attempt is made to support mangling of templates, operator - * overloading, or special functions. - * - * So why don't we use the C++ ABI for D name mangling? - * Because D supports a lot of things (like modules) that the C++ - * ABI has no concept of. These affect every D mangled name, - * so nothing would be compatible anyway. - */ - -/* - * Follows Itanium C++ ABI 1.86 - */ -extern (C++) final class CppMangleVisitor : Visitor -{ - alias visit = super.visit; - Objects components; - OutBuffer buf; - bool is_top_level; - bool components_on; - - void writeBase36(size_t i) - { - if (i >= 36) - { - writeBase36(i / 36); - i %= 36; - } - if (i < 10) - buf.writeByte(cast(char)(i + '0')); - else if (i < 36) - buf.writeByte(cast(char)(i - 10 + 'A')); - else - assert(0); - } - - bool substitute(RootObject p) - { - //printf("substitute %s\n", p ? p.toChars() : null); - if (components_on) - for (size_t i = 0; i < components.dim; i++) - { - //printf(" component[%d] = %s\n", i, components[i] ? components[i].toChars() : null); - if (p == components[i]) - { - //printf("\tmatch\n"); - /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... - */ - buf.writeByte('S'); - if (i) - writeBase36(i - 1); - buf.writeByte('_'); - return true; - } - } - return false; - } - - bool exist(RootObject p) - { - //printf("exist %s\n", p ? p.toChars() : null); - if (components_on) - for (size_t i = 0; i < components.dim; i++) - { - if (p == components[i]) - { - return true; - } - } - return false; - } - - void store(RootObject p) - { - //printf("store %s\n", p ? p.toChars() : "null"); - if (components_on) - components.push(p); - } - - void source_name(Dsymbol s, bool skipname = false) - { - //printf("source_name(%s)\n", s.toChars()); - TemplateInstance ti = s.isTemplateInstance(); - if (ti) - { - if (!skipname && !substitute(ti.tempdecl)) - { - store(ti.tempdecl); - const(char)* name = ti.tempdecl.toAlias().ident.toChars(); - buf.printf("%d%s", strlen(name), name); - } - buf.writeByte('I'); - bool is_var_arg = false; - for (size_t i = 0; i < ti.tiargs.dim; i++) - { - RootObject o = cast(RootObject)(*ti.tiargs)[i]; - TemplateParameter tp = null; - TemplateValueParameter tv = null; - TemplateTupleParameter tt = null; - if (!is_var_arg) - { - TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); - assert(td); - tp = (*td.parameters)[i]; - tv = tp.isTemplateValueParameter(); - tt = tp.isTemplateTupleParameter(); - } - /* - * ::= # type or template - * ::= # simple expressions - */ - if (tt) - { - buf.writeByte('I'); - is_var_arg = true; - tp = null; - } - if (tv) - { - // ::= L E # integer literal - if (tv.valType.isintegral()) - { - Expression e = isExpression(o); - assert(e); - buf.writeByte('L'); - tv.valType.accept(this); - if (tv.valType.isunsigned()) - { - buf.printf("%llu", e.toUInteger()); - } - else - { - sinteger_t val = e.toInteger(); - if (val < 0) - { - val = -val; - buf.writeByte('n'); - } - buf.printf("%lld", val); - } - buf.writeByte('E'); - } - else - { - s.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); - fatal(); - } - } - else if (!tp || tp.isTemplateTypeParameter()) - { - Type t = isType(o); - assert(t); - t.accept(this); - } - else if (tp.isTemplateAliasParameter()) - { - Dsymbol d = isDsymbol(o); - Expression e = isExpression(o); - if (!d && !e) - { - s.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); - fatal(); - } - if (d && d.isFuncDeclaration()) - { - bool is_nested = d.toParent() && !d.toParent().isModule() && (cast(TypeFunction)d.isFuncDeclaration().type).linkage == LINKcpp; - if (is_nested) - buf.writeByte('X'); - buf.writeByte('L'); - mangle_function(d.isFuncDeclaration()); - buf.writeByte('E'); - if (is_nested) - buf.writeByte('E'); - } - else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) - { - VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); - buf.writeByte('L'); - mangle_variable(vd, true); - buf.writeByte('E'); - } - else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) - { - if (!substitute(d)) - { - cpp_mangle_name(d, false); - } - } - else - { - s.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); - fatal(); - } - } - else - { - s.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); - fatal(); - } - } - if (is_var_arg) - { - buf.writeByte('E'); - } - buf.writeByte('E'); - return; - } - else - { - const(char)* name = s.ident.toChars(); - buf.printf("%d%s", strlen(name), name); - } - } - - void prefix_name(Dsymbol s) - { - //printf("prefix_name(%s)\n", s.toChars()); - if (!substitute(s)) - { - Dsymbol p = s.toParent(); - if (p && p.isTemplateInstance()) - { - s = p; - if (exist(p.isTemplateInstance().tempdecl)) - { - p = null; - } - else - { - p = p.toParent(); - } - } - if (p && !p.isModule()) - { - if (p.ident == Id.std && is_initial_qualifier(p)) - buf.writestring("St"); - else - prefix_name(p); - } - if (!(s.ident == Id.std && is_initial_qualifier(s))) - store(s); - source_name(s); - } - } - - /* Is s the initial qualifier? - */ - bool is_initial_qualifier(Dsymbol s) - { - Dsymbol p = s.toParent(); - if (p && p.isTemplateInstance()) - { - if (exist(p.isTemplateInstance().tempdecl)) - { - return true; - } - p = p.toParent(); - } - return !p || p.isModule(); - } - - void cpp_mangle_name(Dsymbol s, bool qualified) - { - //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); - Dsymbol p = s.toParent(); - Dsymbol se = s; - bool dont_write_prefix = false; - if (p && p.isTemplateInstance()) - { - se = p; - if (exist(p.isTemplateInstance().tempdecl)) - dont_write_prefix = true; - p = p.toParent(); - } - if (p && !p.isModule()) - { - /* The N..E is not required if: - * 1. the parent is 'std' - * 2. 'std' is the initial qualifier - * 3. there is no CV-qualifier or a ref-qualifier for a member function - * ABI 5.1.8 - */ - if (p.ident == Id.std && is_initial_qualifier(p) && !qualified) - { - if (s.ident == Id.allocator) - { - buf.writestring("Sa"); // "Sa" is short for ::std::allocator - source_name(se, true); - } - else if (s.ident == Id.basic_string) - { - components_on = false; // turn off substitutions - buf.writestring("Sb"); // "Sb" is short for ::std::basic_string - size_t off = buf.offset; - source_name(se, true); - components_on = true; - // Replace ::std::basic_string < char, ::std::char_traits, ::std::allocator > - // with Ss - //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); - if (buf.offset - off >= 26 && memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE".ptr, 26) == 0) - { - buf.remove(off - 2, 28); - buf.insert(off - 2, "Ss"); - return; - } - buf.setsize(off); - source_name(se, true); - } - else if (s.ident == Id.basic_istream || s.ident == Id.basic_ostream || s.ident == Id.basic_iostream) - { - /* Replace - * ::std::basic_istream > with Si - * ::std::basic_ostream > with So - * ::std::basic_iostream > with Sd - */ - size_t off = buf.offset; - components_on = false; // turn off substitutions - source_name(se, true); - components_on = true; - //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); - if (buf.offset - off >= 21 && memcmp(buf.data + off, "IcSt11char_traitsIcEE".ptr, 21) == 0) - { - buf.remove(off, 21); - char[2] mbuf; - mbuf[0] = 'S'; - mbuf[1] = 'i'; - if (s.ident == Id.basic_ostream) - mbuf[1] = 'o'; - else if (s.ident == Id.basic_iostream) - mbuf[1] = 'd'; - buf.insert(off, mbuf[]); - return; - } - buf.setsize(off); - buf.writestring("St"); - source_name(se); - } - else - { - buf.writestring("St"); - source_name(se); - } - } - else - { - buf.writeByte('N'); - if (!dont_write_prefix) - prefix_name(p); - source_name(se); - buf.writeByte('E'); - } - } - else - source_name(se); - store(s); - } - - void mangle_variable(VarDeclaration d, bool is_temp_arg_ref) - { - // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 - if (!(d.storage_class & (STCextern | STCfield | STCgshared))) - { - d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); - fatal(); - } - Dsymbol p = d.toParent(); - if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" - { - buf.writestring("_ZN"); - prefix_name(p); - source_name(d); - buf.writeByte('E'); - } - else //char beta[6] should mangle as "beta" - { - if (!is_temp_arg_ref) - { - buf.writestring(d.ident.toChars()); - } - else - { - buf.writestring("_Z"); - source_name(d); - } - } - } - - void mangle_function(FuncDeclaration d) - { - //printf("mangle_function(%s)\n", d.toChars()); - /* - * ::= _Z - * ::= - * ::= - * ::= - */ - TypeFunction tf = cast(TypeFunction)d.type; - buf.writestring("_Z"); - Dsymbol p = d.toParent(); - TemplateDeclaration ftd = getFuncTemplateDecl(d); - - if (p && !p.isModule() && tf.linkage == LINKcpp && !ftd) - { - buf.writeByte('N'); - if (d.type.isConst()) - buf.writeByte('K'); - prefix_name(p); - // See ABI 5.1.8 Compression - // Replace ::std::allocator with Sa - if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator".ptr, 17) == 0) - { - buf.remove(3, 14); - buf.insert(3, "Sa"); - } - // Replace ::std::basic_string with Sb - if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string".ptr, 21) == 0) - { - buf.remove(3, 18); - buf.insert(3, "Sb"); - } - // Replace ::std with St - if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std".ptr, 7) == 0) - { - buf.remove(3, 4); - buf.insert(3, "St"); - } - if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std".ptr, 8) == 0) - { - buf.remove(4, 4); - buf.insert(4, "St"); - } - if (d.isDtorDeclaration()) - { - buf.writestring("D1"); - } - else - { - source_name(d); - } - buf.writeByte('E'); - } - else if (ftd) - { - source_name(p); - this.is_top_level = true; - tf.nextOf().accept(this); - this.is_top_level = false; - } - else - { - source_name(d); - } - if (tf.linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling - { - assert(tf.ty == Tfunction); - argsCppMangle(tf.parameters, tf.varargs); - } - } - - void argsCppMangle(Parameters* parameters, int varargs) - { - int paramsCppMangleDg(size_t n, Parameter fparam) - { - Type t = fparam.type.merge2(); - if (fparam.storageClass & (STCout | STCref)) - t = t.referenceTo(); - else if (fparam.storageClass & STClazy) - { - // Mangle as delegate - Type td = new TypeFunction(null, t, 0, LINKd); - td = new TypeDelegate(td); - t = t.merge(); - } - if (t.ty == Tsarray) - { - // Mangle static arrays as pointers - t.error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function."); - t.error(Loc(), "Use pointer instead."); - fatal(); - //t = t.nextOf().pointerTo(); - } - /* If it is a basic, enum or struct type, - * then don't mark it const - */ - this.is_top_level = true; - if ((t.ty == Tenum || t.ty == Tstruct || t.ty == Tpointer || t.isTypeBasic()) && t.isConst()) - t.mutableOf().accept(this); - else - t.accept(this); - this.is_top_level = false; - return 0; - } - - if (parameters) - Parameter._foreach(parameters, ¶msCppMangleDg); - if (varargs) - buf.writestring("z"); - else if (!parameters || !parameters.dim) - buf.writeByte('v'); // encode ( ) parameters - } - -public: - extern (D) this() - { - this.components_on = true; - } - - const(char)* mangleOf(Dsymbol s) - { - VarDeclaration vd = s.isVarDeclaration(); - FuncDeclaration fd = s.isFuncDeclaration(); - if (vd) - { - mangle_variable(vd, false); - } - else if (fd) - { - mangle_function(fd); - } - else - { - assert(0); - } - Target.prefixName(&buf, LINKcpp); - return buf.extractString(); - } - - override void visit(Type t) - { - if (t.isImmutable() || t.isShared()) - { - t.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", t.toChars()); - } - else - { - t.error(Loc(), "Internal Compiler Error: type %s can not be mapped to C++\n", t.toChars()); - } - fatal(); //Fatal, because this error should be handled in frontend - } - - override void visit(TypeBasic t) - { - /* ABI spec says: - * v void - * w wchar_t - * b bool - * c char - * a signed char - * h unsigned char - * s short - * t unsigned short - * i int - * j unsigned int - * l long - * m unsigned long - * x long long, __int64 - * y unsigned long long, __int64 - * n __int128 - * o unsigned __int128 - * f float - * d double - * e long double, __float80 - * g __float128 - * z ellipsis - * u # vendor extended type - */ - char c; - char p = 0; - switch (t.ty) - { - case Tvoid: - c = 'v'; - break; - case Tint8: - c = 'a'; - break; - case Tuns8: - c = 'h'; - break; - case Tint16: - c = 's'; - break; - case Tuns16: - c = 't'; - break; - case Tint32: - c = 'i'; - break; - case Tuns32: - c = 'j'; - break; - case Tfloat32: - c = 'f'; - break; - case Tint64: - c = (Target.c_longsize == 8 ? 'l' : 'x'); - break; - case Tuns64: - c = (Target.c_longsize == 8 ? 'm' : 'y'); - break; - case Tint128: - c = 'n'; - break; - case Tuns128: - c = 'o'; - break; - case Tfloat64: - c = 'd'; - break; - case Tfloat80: - c = 'e'; - break; - case Tbool: - c = 'b'; - break; - case Tchar: - c = 'c'; - break; - case Twchar: - c = 't'; - break; - // unsigned short - case Tdchar: - c = 'w'; - break; - // wchar_t (UTF-32) - case Timaginary32: - p = 'G'; - c = 'f'; - break; - case Timaginary64: - p = 'G'; - c = 'd'; - break; - case Timaginary80: - p = 'G'; - c = 'e'; - break; - case Tcomplex32: - p = 'C'; - c = 'f'; - break; - case Tcomplex64: - p = 'C'; - c = 'd'; - break; - case Tcomplex80: - p = 'C'; - c = 'e'; - break; - default: - visit(cast(Type)t); - return; - } - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (p || t.isConst()) - { - if (substitute(t)) - { - return; - } - else - { - store(t); - } - } - if (t.isConst()) - buf.writeByte('K'); - - // Handle any target-specific basic types. - if (auto tm = Target.cppTypeMangle(t)) - { - buf.writestring(tm); - } - else - { - if (p) - buf.writeByte(p); - buf.writeByte(c); - } - } - - override void visit(TypeVector t) - { - is_top_level = false; - if (substitute(t)) - return; - store(t); - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - - // Handle any target-specific vector types. - if (auto tm = Target.cppTypeMangle(t)) - { - buf.writestring(tm); - } - else - { - assert(t.basetype && t.basetype.ty == Tsarray); - assert((cast(TypeSArray)t.basetype).dim); - //buf.printf("Dv%llu_", ((TypeSArray *)t.basetype).dim.toInteger());// -- Gnu ABI v.4 - buf.writestring("U8__vector"); //-- Gnu ABI v.3 - t.basetype.nextOf().accept(this); - } - } - - override void visit(TypeSArray t) - { - is_top_level = false; - if (!substitute(t)) - store(t); - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - buf.printf("A%llu_", t.dim ? t.dim.toInteger() : 0); - t.next.accept(this); - } - - override void visit(TypeDArray t) - { - visit(cast(Type)t); - } - - override void visit(TypeAArray t) - { - visit(cast(Type)t); - } - - override void visit(TypePointer t) - { - is_top_level = false; - if (substitute(t)) - return; - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - buf.writeByte('P'); - t.next.accept(this); - store(t); - } - - override void visit(TypeReference t) - { - is_top_level = false; - if (substitute(t)) - return; - buf.writeByte('R'); - t.next.accept(this); - store(t); - } - - override void visit(TypeFunction t) - { - is_top_level = false; - /* - * ::= F [Y] E - * ::= + - * # types are possible return type, then parameter types - */ - /* ABI says: - "The type of a non-static member function is considered to be different, - for the purposes of substitution, from the type of a namespace-scope or - static member function whose type appears similar. The types of two - non-static member functions are considered to be different, for the - purposes of substitution, if the functions are members of different - classes. In other words, for the purposes of substitution, the class of - which the function is a member is considered part of the type of - function." - - BUG: Right now, types of functions are never merged, so our simplistic - component matcher always finds them to be different. - We should use Type.equals on these, and use different - TypeFunctions for non-static member functions, and non-static - member functions of different classes. - */ - if (substitute(t)) - return; - buf.writeByte('F'); - if (t.linkage == LINKc) - buf.writeByte('Y'); - Type tn = t.next; - if (t.isref) - tn = tn.referenceTo(); - tn.accept(this); - argsCppMangle(t.parameters, t.varargs); - buf.writeByte('E'); - store(t); - } - - override void visit(TypeDelegate t) - { - visit(cast(Type)t); - } - - override void visit(TypeStruct t) - { - const id = t.sym.ident; - //printf("struct id = '%s'\n", id.toChars()); - char c; - if (id == Id.__c_long) - c = 'l'; - else if (id == Id.__c_ulong) - c = 'm'; - else - c = 0; - if (c) - { - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - { - if (substitute(t)) - { - return; - } - else - { - store(t); - } - } - if (t.isConst()) - buf.writeByte('K'); - buf.writeByte(c); - return; - } - is_top_level = false; - if (substitute(t)) - return; - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - - // Handle any target-specific struct types. - if (auto tm = Target.cppTypeMangle(t)) - { - buf.writestring(tm); - } - else - { - if (!substitute(t.sym)) - { - cpp_mangle_name(t.sym, t.isConst()); - } - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - } - if (t.isConst()) - store(t); - } - - override void visit(TypeEnum t) - { - is_top_level = false; - if (substitute(t)) - return; - if (t.isConst()) - buf.writeByte('K'); - if (!substitute(t.sym)) - { - cpp_mangle_name(t.sym, t.isConst()); - } - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - store(t); - } - - override void visit(TypeClass t) - { - if (substitute(t)) - return; - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst() && !is_top_level) - buf.writeByte('K'); - is_top_level = false; - buf.writeByte('P'); - if (t.isConst()) - buf.writeByte('K'); - if (!substitute(t.sym)) - { - cpp_mangle_name(t.sym, t.isConst()); - } - if (t.isConst()) - store(null); - store(t); - } - - final const(char)* mangle_typeinfo(Dsymbol s) - { - buf.writestring("_ZTI"); - cpp_mangle_name(s, false); - return buf.extractString(); - } -} - -extern (C++) const(char)* toCppMangleItanium(Dsymbol s) -{ - //printf("toCppMangleItanium(%s)\n", s.toChars()); - scope CppMangleVisitor v = new CppMangleVisitor(); - return v.mangleOf(s); -} - -extern (C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s) -{ - //printf("cppTypeInfoMangle(%s)\n", s.toChars()); - scope CppMangleVisitor v = new CppMangleVisitor(); - return v.mangle_typeinfo(s); -} - -// Windows DMC and Microsoft Visual C++ mangling -enum VC_SAVED_TYPE_CNT = 10u; -enum VC_SAVED_IDENT_CNT = 10u; - -extern (C++) final class VisualCPPMangler : Visitor -{ - alias visit = super.visit; - const(char)*[VC_SAVED_IDENT_CNT] saved_idents; - Type[VC_SAVED_TYPE_CNT] saved_types; - - // IS_NOT_TOP_TYPE: when we mangling one argument, we can call visit several times (for base types of arg type) - // but we must save only arg type: - // For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int" - // This flag is set up by the visit(NextType, ) function and should be reset when the arg type output is finished. - // MANGLE_RETURN_TYPE: return type shouldn't be saved and substituted in arguments - // IGNORE_CONST: in some cases we should ignore CV-modifiers. - - enum Flags : int - { - IS_NOT_TOP_TYPE = 0x1, - MANGLE_RETURN_TYPE = 0x2, - IGNORE_CONST = 0x4, - IS_DMC = 0x8, - } - - alias IS_NOT_TOP_TYPE = Flags.IS_NOT_TOP_TYPE; - alias MANGLE_RETURN_TYPE = Flags.MANGLE_RETURN_TYPE; - alias IGNORE_CONST = Flags.IGNORE_CONST; - alias IS_DMC = Flags.IS_DMC; - - int flags; - OutBuffer buf; - - extern (D) this(VisualCPPMangler rvl) - { - flags |= (rvl.flags & IS_DMC); - memcpy(&saved_idents, &rvl.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); - memcpy(&saved_types, &rvl.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT); - } - -public: - extern (D) this(bool isdmc) - { - if (isdmc) - { - flags |= IS_DMC; - } - memset(&saved_idents, 0, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); - memset(&saved_types, 0, Type.sizeof * VC_SAVED_TYPE_CNT); - } - - override void visit(Type type) - { - if (type.isImmutable() || type.isShared()) - { - type.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", type.toChars()); - } - else - { - type.error(Loc(), "Internal Compiler Error: type %s can not be mapped to C++\n", type.toChars()); - } - fatal(); //Fatal, because this error should be handled in frontend - } - - override void visit(TypeBasic type) - { - //printf("visit(TypeBasic); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) - { - if (checkTypeSaved(type)) - return; - } - if ((type.ty == Tbool) && checkTypeSaved(type)) // try to replace long name with number - { - return; - } - if (!(flags & IS_DMC)) - { - switch (type.ty) - { - case Tint64: - case Tuns64: - case Tint128: - case Tuns128: - case Tfloat80: - case Twchar: - if (checkTypeSaved(type)) - return; - break; - - default: - break; - } - } - mangleModifier(type); - switch (type.ty) - { - case Tvoid: - buf.writeByte('X'); - break; - case Tint8: - buf.writeByte('C'); - break; - case Tuns8: - buf.writeByte('E'); - break; - case Tint16: - buf.writeByte('F'); - break; - case Tuns16: - buf.writeByte('G'); - break; - case Tint32: - buf.writeByte('H'); - break; - case Tuns32: - buf.writeByte('I'); - break; - case Tfloat32: - buf.writeByte('M'); - break; - case Tint64: - buf.writestring("_J"); - break; - case Tuns64: - buf.writestring("_K"); - break; - case Tint128: - buf.writestring("_L"); - break; - case Tuns128: - buf.writestring("_M"); - break; - case Tfloat64: - buf.writeByte('N'); - break; - case Tbool: - buf.writestring("_N"); - break; - case Tchar: - buf.writeByte('D'); - break; - case Tdchar: - buf.writeByte('I'); - break; - // unsigned int - case Tfloat80: - if (flags & IS_DMC) - buf.writestring("_Z"); // DigitalMars long double - else - buf.writestring("_T"); // Intel long double - break; - case Twchar: - if (flags & IS_DMC) - buf.writestring("_Y"); // DigitalMars wchar_t - else - buf.writestring("_W"); // Visual C++ wchar_t - break; - default: - visit(cast(Type)type); - return; - } - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - override void visit(TypeVector type) - { - //printf("visit(TypeVector); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - buf.writestring("T__m128@@"); // may be better as __m128i or __m128d? - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - override void visit(TypeSArray type) - { - // This method can be called only for static variable type mangling. - //printf("visit(TypeSArray); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - // first dimension always mangled as const pointer - if (flags & IS_DMC) - buf.writeByte('Q'); - else - buf.writeByte('P'); - flags |= IS_NOT_TOP_TYPE; - assert(type.next); - if (type.next.ty == Tsarray) - { - mangleArray(cast(TypeSArray)type.next); - } - else - { - type.next.accept(this); - } - } - - // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation) - // There is not way to map int C++ (*arr)[2][1] to D - override void visit(TypePointer type) - { - //printf("visit(TypePointer); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - assert(type.next); - if (type.next.ty == Tfunction) - { - const(char)* arg = mangleFunctionType(cast(TypeFunction)type.next); // compute args before checking to save; args should be saved before function type - // If we've mangled this function early, previous call is meaningless. - // However we should do it before checking to save types of function arguments before function type saving. - // If this function was already mangled, types of all it arguments are save too, thus previous can't save - // anything if function is saved. - if (checkTypeSaved(type)) - return; - if (type.isConst()) - buf.writeByte('Q'); // const - else - buf.writeByte('P'); // mutable - buf.writeByte('6'); // pointer to a function - buf.writestring(arg); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - return; - } - else if (type.next.ty == Tsarray) - { - if (checkTypeSaved(type)) - return; - mangleModifier(type); - if (type.isConst() || !(flags & IS_DMC)) - buf.writeByte('Q'); // const - else - buf.writeByte('P'); // mutable - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - mangleArray(cast(TypeSArray)type.next); - return; - } - else - { - if (checkTypeSaved(type)) - return; - mangleModifier(type); - if (type.isConst()) - { - buf.writeByte('Q'); // const - } - else - { - buf.writeByte('P'); // mutable - } - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - type.next.accept(this); - } - } - - override void visit(TypeReference type) - { - //printf("visit(TypeReference); type = %s\n", type.toChars()); - if (checkTypeSaved(type)) - return; - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - buf.writeByte('A'); // mutable - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - assert(type.next); - if (type.next.ty == Tsarray) - { - mangleArray(cast(TypeSArray)type.next); - } - else - { - type.next.accept(this); - } - } - - override void visit(TypeFunction type) - { - const(char)* arg = mangleFunctionType(type); - if ((flags & IS_DMC)) - { - if (checkTypeSaved(type)) - return; - } - else - { - buf.writestring("$$A6"); - } - buf.writestring(arg); - flags &= ~(IS_NOT_TOP_TYPE | IGNORE_CONST); - } - - override void visit(TypeStruct type) - { - const id = type.sym.ident; - char c; - if (id == Id.__c_long_double) - c = 'O'; // VC++ long double - else if (id == Id.__c_long) - c = 'J'; // VC++ long - else if (id == Id.__c_ulong) - c = 'K'; // VC++ unsigned long - else - c = 0; - if (c) - { - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) - { - if (checkTypeSaved(type)) - return; - } - mangleModifier(type); - buf.writeByte(c); - } - else - { - if (checkTypeSaved(type)) - return; - //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - mangleModifier(type); - if (type.sym.isUnionDeclaration()) - buf.writeByte('T'); - else - buf.writeByte(type.cppmangle == CPPMANGLE.asClass ? 'V' : 'U'); - mangleIdent(type.sym); - } - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - override void visit(TypeEnum type) - { - //printf("visit(TypeEnum); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - mangleModifier(type); - buf.writeByte('W'); - switch (type.sym.memtype.ty) - { - case Tchar: - case Tint8: - buf.writeByte('0'); - break; - case Tuns8: - buf.writeByte('1'); - break; - case Tint16: - buf.writeByte('2'); - break; - case Tuns16: - buf.writeByte('3'); - break; - case Tint32: - buf.writeByte('4'); - break; - case Tuns32: - buf.writeByte('5'); - break; - case Tint64: - buf.writeByte('6'); - break; - case Tuns64: - buf.writeByte('7'); - break; - default: - visit(cast(Type)type); - break; - } - mangleIdent(type.sym); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - // D class mangled as pointer to C++ class - // const(Object) mangled as Object const* const - override void visit(TypeClass type) - { - //printf("visit(TypeClass); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - if (flags & IS_NOT_TOP_TYPE) - mangleModifier(type); - if (type.isConst()) - buf.writeByte('Q'); - else - buf.writeByte('P'); - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - mangleModifier(type); - buf.writeByte(type.cppmangle == CPPMANGLE.asStruct ? 'U' : 'V'); - mangleIdent(type.sym); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - const(char)* mangleOf(Dsymbol s) - { - VarDeclaration vd = s.isVarDeclaration(); - FuncDeclaration fd = s.isFuncDeclaration(); - if (vd) - { - mangleVariable(vd); - } - else if (fd) - { - mangleFunction(fd); - } - else - { - assert(0); - } - return buf.extractString(); - } - -private: - void mangleFunction(FuncDeclaration d) - { - // ? - assert(d); - buf.writeByte('?'); - mangleIdent(d); - if (d.needThis()) // ::= - { - // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ - //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", - //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); - if (d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) - { - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('E'); - break; - case PROTprotected: - buf.writeByte('M'); - break; - default: - buf.writeByte('U'); - break; - } - } - else - { - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('A'); - break; - case PROTprotected: - buf.writeByte('I'); - break; - default: - buf.writeByte('Q'); - break; - } - } - if (global.params.is64bit) - buf.writeByte('E'); - if (d.type.isConst()) - { - buf.writeByte('B'); - } - else - { - buf.writeByte('A'); - } - } - else if (d.isMember2()) // static function - { - // ::= - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('C'); - break; - case PROTprotected: - buf.writeByte('K'); - break; - default: - buf.writeByte('S'); - break; - } - } - else // top-level function - { - // ::= Y - buf.writeByte('Y'); - } - const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration()); - buf.writestring(args); - } - - void mangleVariable(VarDeclaration d) - { - // ::= ? - assert(d); - // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 - if (!(d.storage_class & (STCextern | STCfield | STCgshared))) - { - d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); - fatal(); - } - buf.writeByte('?'); - mangleIdent(d); - assert((d.storage_class & STCfield) || !d.needThis()); - Dsymbol parent = d.toParent(); - while (parent && parent.isNspace()) - { - parent = parent.toParent(); - } - if (parent && parent.isModule()) // static member - { - buf.writeByte('3'); - } - else - { - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('0'); - break; - case PROTprotected: - buf.writeByte('1'); - break; - default: - buf.writeByte('2'); - break; - } - } - char cv_mod = 0; - Type t = d.type; - if (t.isImmutable() || t.isShared()) - { - visit(t); - return; - } - if (t.isConst()) - { - cv_mod = 'B'; // const - } - else - { - cv_mod = 'A'; // mutable - } - if (t.ty != Tpointer) - t = t.mutableOf(); - t.accept(this); - if ((t.ty == Tpointer || t.ty == Treference || t.ty == Tclass) && global.params.is64bit) - { - buf.writeByte('E'); - } - buf.writeByte(cv_mod); - } - - void mangleName(Dsymbol sym, bool dont_use_back_reference = false) - { - //printf("mangleName('%s')\n", sym.toChars()); - const(char)* name = null; - bool is_dmc_template = false; - if (sym.isDtorDeclaration()) - { - buf.writestring("?1"); - return; - } - if (TemplateInstance ti = sym.isTemplateInstance()) - { - scope VisualCPPMangler tmp = new VisualCPPMangler((flags & IS_DMC) ? true : false); - tmp.buf.writeByte('?'); - tmp.buf.writeByte('$'); - tmp.buf.writestring(ti.name.toChars()); - tmp.saved_idents[0] = ti.name.toChars(); - tmp.buf.writeByte('@'); - if (flags & IS_DMC) - { - tmp.mangleIdent(sym.parent, true); - is_dmc_template = true; - } - bool is_var_arg = false; - for (size_t i = 0; i < ti.tiargs.dim; i++) - { - RootObject o = (*ti.tiargs)[i]; - TemplateParameter tp = null; - TemplateValueParameter tv = null; - TemplateTupleParameter tt = null; - if (!is_var_arg) - { - TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); - assert(td); - tp = (*td.parameters)[i]; - tv = tp.isTemplateValueParameter(); - tt = tp.isTemplateTupleParameter(); - } - if (tt) - { - is_var_arg = true; - tp = null; - } - if (tv) - { - if (tv.valType.isintegral()) - { - tmp.buf.writeByte('$'); - tmp.buf.writeByte('0'); - Expression e = isExpression(o); - assert(e); - if (tv.valType.isunsigned()) - { - tmp.mangleNumber(e.toUInteger()); - } - else if (is_dmc_template) - { - // NOTE: DMC mangles everything based on - // unsigned int - tmp.mangleNumber(e.toInteger()); - } - else - { - sinteger_t val = e.toInteger(); - if (val < 0) - { - val = -val; - tmp.buf.writeByte('?'); - } - tmp.mangleNumber(val); - } - } - else - { - sym.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); - fatal(); - } - } - else if (!tp || tp.isTemplateTypeParameter()) - { - Type t = isType(o); - assert(t); - t.accept(tmp); - } - else if (tp.isTemplateAliasParameter()) - { - Dsymbol d = isDsymbol(o); - Expression e = isExpression(o); - if (!d && !e) - { - sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); - fatal(); - } - if (d && d.isFuncDeclaration()) - { - tmp.buf.writeByte('$'); - tmp.buf.writeByte('1'); - tmp.mangleFunction(d.isFuncDeclaration()); - } - else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) - { - tmp.buf.writeByte('$'); - if (flags & IS_DMC) - tmp.buf.writeByte('1'); - else - tmp.buf.writeByte('E'); - tmp.mangleVariable((cast(VarExp)e).var.isVarDeclaration()); - } - else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) - { - Dsymbol ds = d.isTemplateDeclaration().onemember; - if (flags & IS_DMC) - { - tmp.buf.writeByte('V'); - } - else - { - if (ds.isUnionDeclaration()) - { - tmp.buf.writeByte('T'); - } - else if (ds.isStructDeclaration()) - { - tmp.buf.writeByte('U'); - } - else if (ds.isClassDeclaration()) - { - tmp.buf.writeByte('V'); - } - else - { - sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); - fatal(); - } - } - tmp.mangleIdent(d); - } - else - { - sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); - fatal(); - } - } - else - { - sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); - fatal(); - } - } - name = tmp.buf.extractString(); - } - else - { - name = sym.ident.toChars(); - } - assert(name); - if (is_dmc_template) - { - if (checkAndSaveIdent(name)) - return; - } - else - { - if (dont_use_back_reference) - { - saveIdent(name); - } - else - { - if (checkAndSaveIdent(name)) - return; - } - } - buf.writestring(name); - buf.writeByte('@'); - } - - // returns true if name already saved - bool checkAndSaveIdent(const(char)* name) - { - foreach (i; 0 .. VC_SAVED_IDENT_CNT) - { - if (!saved_idents[i]) // no saved same name - { - saved_idents[i] = name; - break; - } - if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name - { - buf.writeByte(i + '0'); - return true; - } - } - return false; - } - - void saveIdent(const(char)* name) - { - foreach (i; 0 .. VC_SAVED_IDENT_CNT) - { - if (!saved_idents[i]) // no saved same name - { - saved_idents[i] = name; - break; - } - if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name - { - return; - } - } - } - - void mangleIdent(Dsymbol sym, bool dont_use_back_reference = false) - { - // ::= @ - // ::= - // ::= - // ::= @ - // ::= ?$ @