From be08ec96063be8c1a1a8621eccd05a4ebeecfb42 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Thu, 20 Apr 2017 21:21:19 +0000 Subject: [PATCH 01/10] Vendor import of lld trunk r300890: https://llvm.org/svn/llvm-project/lld/trunk@300890 --- COFF/Driver.cpp | 8 ++--- COFF/DriverUtils.cpp | 2 +- ELF/Config.h | 1 + ELF/Driver.cpp | 13 ++++++++ ELF/LinkerScript.cpp | 50 ++++++++++++++++++++++++++++++ ELF/LinkerScript.h | 1 + ELF/Options.td | 3 ++ ELF/OutputSections.cpp | 42 +++++++++++++++++++++++++ ELF/OutputSections.h | 5 +++ ELF/Writer.cpp | 47 ++++++---------------------- test/COFF/msvclto.ll | 3 +- test/ELF/compress-debug-sections.s | 32 +++++++++++++++++++ test/ELF/tls-offset.s | 16 ++++++++-- 13 files changed, 177 insertions(+), 46 deletions(-) create mode 100644 test/ELF/compress-debug-sections.s diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 3e7f10bf8d1..daddfb86d4c 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -509,7 +509,7 @@ filterBitcodeFiles(StringRef Path, std::vector &TemporaryFiles) { // Create response file contents and invoke the MSVC linker. void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { - std::string Rsp = "/nologo "; + std::string Rsp = "/nologo\n"; std::vector Temps; for (auto *Arg : Args) { @@ -528,14 +528,14 @@ void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { case OPT_INPUT: { if (Optional Path = doFindFile(Arg->getValue())) { if (Optional S = filterBitcodeFiles(*Path, Temps)) - Rsp += quote(*S) + " "; + Rsp += quote(*S) + "\n"; continue; } - Rsp += quote(Arg->getValue()) + " "; + Rsp += quote(Arg->getValue()) + "\n"; break; } default: - Rsp += toString(Arg) + " "; + Rsp += toString(Arg) + "\n"; } } diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index a9c1c9d5593..2c9ba797f73 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -634,7 +634,7 @@ void runMSVCLinker(std::string Rsp, ArrayRef Objects) { std::vector Temps; for (StringRef S : Objects) { Temps.emplace_back("lto", "obj", S); - Rsp += quote(Temps.back().Path) + " "; + Rsp += quote(Temps.back().Path) + "\n"; } log("link.exe " + Rsp); diff --git a/ELF/Config.h b/ELF/Config.h index c8eecec7439..d25c63c3c0d 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -104,6 +104,7 @@ struct Configuration { bool Bsymbolic; bool BsymbolicFunctions; bool ColorDiagnostics = false; + bool CompressDebugSections; bool DefineCommon; bool Demangle = true; bool DisableVerify; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 47ecd607a48..93924e4554c 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -45,6 +45,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" @@ -564,12 +565,24 @@ static std::vector getLines(MemoryBufferRef MB) { return Ret; } +static bool getCompressDebugSections(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_compress_debug_sections)) { + StringRef S = Arg->getValue(); + if (S == "zlib") + return zlib::isAvailable(); + if (S != "none") + error("unknown --compress-debug-sections value: " + S); + } + return false; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); Config->AuxiliaryList = getArgs(Args, OPT_auxiliary); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->CompressDebugSections = getCompressDebugSections(Args); Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common, !Args.hasArg(OPT_relocatable)); Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true); diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index ab2ca22e9e1..63eb90456e1 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -413,6 +413,56 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { CurOutSec = nullptr; } +void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) { + std::vector Commands; + + // Define start address + uint64_t StartAddr = Config->ImageBase; + if (AllocateHeader) + StartAddr += elf::getHeaderSize(); + + // The Sections with -T
are sorted in order of ascending address + // we must use this if it is lower than StartAddr as calls to setDot() must + // be monotonically increasing + if (!Config->SectionStartMap.empty()) { + uint64_t LowestSecStart = Config->SectionStartMap.begin()->second; + StartAddr = std::min(StartAddr, LowestSecStart); + } + Commands.push_back( + make(".", [=] { return StartAddr; }, "")); + + // For each OutputSection that needs a VA fabricate an OutputSectionCommand + // with an InputSectionDescription describing the InputSections + for (OutputSection *Sec : *OutputSections) { + if (!(Sec->Flags & SHF_ALLOC)) + continue; + + auto I = Config->SectionStartMap.find(Sec->Name); + if (I != Config->SectionStartMap.end()) + Commands.push_back( + make(".", [=] { return I->second; }, "")); + + auto *OSCmd = make(Sec->Name); + OSCmd->Sec = Sec; + if (Sec->PageAlign) + OSCmd->AddrExpr = [=] { + return alignTo(Script->getDot(), Config->MaxPageSize); + }; + Commands.push_back(OSCmd); + if (Sec->Sections.size()) { + auto *ISD = make(""); + OSCmd->Commands.push_back(ISD); + for (InputSection *ISec : Sec->Sections) { + ISD->Sections.push_back(ISec); + ISec->Assigned = true; + } + } + } + // SECTIONS commands run before other non SECTIONS commands + Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end()); + Opt.Commands = std::move(Commands); +} + // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { for (InputSectionBase *S : InputSections) diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index 04a388efb4e..61942b2db35 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -256,6 +256,7 @@ public: bool isDefined(StringRef S); std::vector *OutputSections; + void fabricateDefaultCommands(bool AllocateHeader); void addOrphanSections(OutputSectionFactory &Factory); void removeEmptyCommands(); void adjustSectionsBeforeSorting(); diff --git a/ELF/Options.td b/ELF/Options.td index 7ed8dfb090b..4cf14c9011c 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -22,6 +22,9 @@ def build_id: F<"build-id">, HelpText<"Generate build ID note">; def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">; +def compress_debug_sections : J<"compress-debug-sections=">, + HelpText<"Compress DWARF debug sections">; + def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, HelpText<"Add a directory to the library search path">; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index 93f83100a74..a40818d2d30 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -16,6 +16,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" @@ -83,6 +84,33 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) { return LA->OutSecOff < LB->OutSecOff; } +// Compress section contents if this section contains debug info. +template void OutputSection::maybeCompress() { + typedef typename ELFT::Chdr Elf_Chdr; + + // Compress only DWARF debug sections. + if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) || + !Name.startswith(".debug_")) + return; + + // Create a section header. + ZDebugHeader.resize(sizeof(Elf_Chdr)); + auto *Hdr = reinterpret_cast(ZDebugHeader.data()); + Hdr->ch_type = ELFCOMPRESS_ZLIB; + Hdr->ch_size = Size; + Hdr->ch_addralign = Alignment; + + // Write section contents to a temporary buffer and compress it. + std::vector Buf(Size); + writeTo(Buf.data()); + if (Error E = zlib::compress(toStringRef(Buf), CompressedData)) + fatal("compress failed: " + llvm::toString(std::move(E))); + + // Update section headers. + Size = sizeof(Elf_Chdr) + CompressedData.size(); + Flags |= SHF_COMPRESSED; +} + template void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { std::sort(Sections.begin(), Sections.end(), compareByFilePosition); @@ -245,6 +273,15 @@ uint32_t OutputSection::getFiller() { template void OutputSection::writeTo(uint8_t *Buf) { Loc = Buf; + // We may have already rendered compressed content when using + // -compress-debug-sections option. Write it together with header. + if (!CompressedData.empty()) { + memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size()); + memcpy(Buf + ZDebugHeader.size(), CompressedData.data(), + CompressedData.size()); + return; + } + // Write leading padding. uint32_t Filler = getFiller(); if (Filler) @@ -422,6 +459,11 @@ template void OutputSection::finalize(); template void OutputSection::finalize(); template void OutputSection::finalize(); +template void OutputSection::maybeCompress(); +template void OutputSection::maybeCompress(); +template void OutputSection::maybeCompress(); +template void OutputSection::maybeCompress(); + template void OutputSection::writeTo(uint8_t *Buf); template void OutputSection::writeTo(uint8_t *Buf); template void OutputSection::writeTo(uint8_t *Buf); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 0ae3df5f785..bcda77d1a26 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -84,9 +84,14 @@ public: uint32_t getFiller(); template void writeTo(uint8_t *Buf); template void finalize(); + template void maybeCompress(); void assignOffsets(); std::vector Sections; + // Used for implementation of --compress-debug-sections option. + std::vector ZDebugHeader; + llvm::SmallVector CompressedData; + // Location in the output buffer. uint8_t *Loc = nullptr; }; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 3ded0c675b8..e8718c258c7 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -19,6 +19,7 @@ #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" +#include "Threads.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" @@ -58,7 +59,6 @@ private: std::vector createPhdrs(); void removeEmptyPTLoad(); void addPtArmExid(std::vector &Phdrs); - void assignAddresses(); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); @@ -250,13 +250,11 @@ template void Writer::run() { if (Config->Relocatable) { assignFileOffsets(); } else { - if (Script->Opt.HasSections) { - Script->assignAddresses(Phdrs); - } else { + if (!Script->Opt.HasSections) { fixSectionAlignments(); - assignAddresses(); - Script->processNonSectionCommands(); + Script->fabricateDefaultCommands(Config->MaxPageSize); } + Script->assignAddresses(Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses @@ -1216,6 +1214,12 @@ template void Writer::finalizeSections() { for (OutputSection *Sec : OutputSections) Sec->finalize(); + // If -compressed-debug-sections is specified, we need to compress + // .debug_* sections. Do it right now because it changes the size of + // output sections. + parallelForEach(OutputSections.begin(), OutputSections.end(), + [](OutputSection *S) { S->maybeCompress(); }); + // createThunks may have added local symbols to the static symbol table applySynthetic({In::SymTab, In::ShStrTab, In::StrTab}, [](SyntheticSection *SS) { SS->postThunkContents(); }); @@ -1502,37 +1506,6 @@ template void Writer::fixHeaders() { AllocateHeader = allocateHeaders(Phdrs, OutputSections, Min); } -// Assign VAs (addresses at run-time) to output sections. -template void Writer::assignAddresses() { - uint64_t VA = Config->ImageBase; - uint64_t ThreadBssOffset = 0; - - if (AllocateHeader) - VA += getHeaderSize(); - - for (OutputSection *Sec : OutputSections) { - uint32_t Alignment = Sec->Alignment; - if (Sec->PageAlign) - Alignment = std::max(Alignment, Config->MaxPageSize); - - auto I = Config->SectionStartMap.find(Sec->Name); - if (I != Config->SectionStartMap.end()) - VA = I->second; - - // We only assign VAs to allocated sections. - if (needsPtLoad(Sec)) { - VA = alignTo(VA, Alignment); - Sec->Addr = VA; - VA += Sec->Size; - } else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) { - uint64_t TVA = VA + ThreadBssOffset; - TVA = alignTo(TVA, Alignment); - Sec->Addr = TVA; - ThreadBssOffset = TVA - VA + Sec->Size; - } - } -} - // Adjusts the file alignment for a given output section and returns // its new file offset. The file offset must be the same with its // virtual address (modulo the page size) so that the loader can load diff --git a/test/COFF/msvclto.ll b/test/COFF/msvclto.ll index e8a6b5c49ce..7fa9c54711b 100644 --- a/test/COFF/msvclto.ll +++ b/test/COFF/msvclto.ll @@ -5,7 +5,8 @@ ; RUN: /entry:main /verbose > %t.log || true ; RUN: FileCheck %s < %t.log -; CHECK: /opt:icf /entry:main /verbose +; CHECK: /opt:icf /entry:main +; CHECK: /verbose target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc" diff --git a/test/ELF/compress-debug-sections.s b/test/ELF/compress-debug-sections.s new file mode 100644 index 00000000000..5fb7ee515dc --- /dev/null +++ b/test/ELF/compress-debug-sections.s @@ -0,0 +1,32 @@ +# REQUIRES: x86, zlib + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t1 --compress-debug-sections=zlib + +# RUN: llvm-objdump -s %t1 | FileCheck %s --check-prefix=ZLIBCONTENT +# ZLIBCONTENT: Contents of section .debug_str: +# ZLIBCONTENT-NOT: AAAAAAAAA + +# RUN: llvm-readobj -s %t1 | FileCheck %s --check-prefix=ZLIBFLAGS +# ZLIBFLAGS: Section { +# ZLIBFLAGS: Index: +# ZLIBFLAGS: Name: .debug_str +# ZLIBFLAGS-NEXT: Type: SHT_PROGBITS +# ZLIBFLAGS-NEXT: Flags [ +# ZLIBFLAGS-NEXT: SHF_COMPRESSED + +# RUN: llvm-dwarfdump %t1 -debug-dump=str | \ +# RUN: FileCheck %s --check-prefix=DEBUGSTR +# DEBUGSTR: .debug_str contents: +# DEBUGSTR-NEXT: AAAAAAAAAAAAAAAAAAAAAAAAAAA +# DEBUGSTR-NEXT: BBBBBBBBBBBBBBBBBBBBBBBBBBB + +# RUN: not ld.lld %t.o -o %t1 --compress-debug-sections=zlib-gabi 2>&1 | \ +# RUN: FileCheck -check-prefix=ERR %s +# ERR: unknown --compress-debug-sections value: zlib-gabi + +.section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "AAAAAAAAAAAAAAAAAAAAAAAAAAA" +.Linfo_string1: + .asciz "BBBBBBBBBBBBBBBBBBBBBBBBBBB" diff --git a/test/ELF/tls-offset.s b/test/ELF/tls-offset.s index ad921af8eff..062def4e14f 100644 --- a/test/ELF/tls-offset.s +++ b/test/ELF/tls-offset.s @@ -2,7 +2,17 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: ld.lld %t -o %tout // RUN: llvm-readobj -s %tout | FileCheck %s - +// RUN: echo "SECTIONS { \ +// RUN: . = 0x201000; \ +// RUN: .text : { *(.text) } \ +// RUN: . = 0x202000; \ +// RUN: .tdata : { *(.tdata) } \ +// RUN: .tbss : { *(.tbss) } \ +// RUN: .data.rel.ro : { *(.data.rel.ro) } \ +// RUN: }" > %t.script + // RUN: ld.lld -T %t.script %t -o %tout2 +// RUN: echo SCRIPT +// RUN: llvm-readobj -s %tout2 | FileCheck %s .global _start _start: retq @@ -51,6 +61,6 @@ _start: // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: SHF_WRITE // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x202004 -// CHECK-NEXT: Offset: 0x2004 +// CHECK-NEXT: Address: 0x202010 +// CHECK-NEXT: Offset: 0x2010 // CHECK-NEXT: Size: 4 From 2fa809d9eabddd820af54059faa8362dd50b51de Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 26 Apr 2017 19:24:31 +0000 Subject: [PATCH 02/10] Vendor import of libc++ trunk r301441: https://llvm.org/svn/llvm-project/libcxx/trunk@301441 --- CMakeLists.txt | 20 ++--- include/atomic | 33 ++++--- include/math.h | 89 +++++++++++++++++-- include/mutex | 2 +- .../diagnose_invalid_memory_order.fail.cpp | 4 + .../new_faligned_allocation.sh.cpp | 6 +- .../conversions.string/ctor_move.pass.cpp | 3 + test/libcxx/modules/cinttypes_exports.sh.cpp | 4 + test/libcxx/modules/clocale_exports.sh.cpp | 4 + test/libcxx/modules/cstdint_exports.sh.cpp | 4 + test/libcxx/modules/inttypes_h_exports.sh.cpp | 4 + .../futures.promise/set_exception.pass.cpp | 3 + .../set_exception_at_thread_exit.pass.cpp | 4 +- .../thread_safety_lock_guard.pass.cpp | 4 + .../thread_safety_lock_unlock.pass.cpp | 4 + .../thread_safety_missing_unlock.fail.cpp | 4 + ...thread_safety_requires_capability.pass.cpp | 4 + .../except.nested/assign.pass.cpp | 3 + .../except.nested/ctor_copy.pass.cpp | 3 + .../except.nested/ctor_default.pass.cpp | 3 + .../except.nested/rethrow_if_nested.pass.cpp | 5 +- .../except.nested/rethrow_nested.pass.cpp | 3 + .../except.nested/throw_with_nested.pass.cpp | 3 + .../propagation/current_exception.pass.cpp | 3 + .../propagation/exception_ptr.pass.cpp | 3 + .../propagation/make_exception_ptr.pass.cpp | 3 + .../propagation/rethrow_exception.pass.cpp | 3 + test/std/numerics/c.math/cmath.pass.cpp | 33 +++++++ .../string.cons/T_size_size.pass.cpp | 1 - .../any.class/any.modifiers/emplace.pass.cpp | 26 +++--- .../optional.object.assign/emplace.pass.cpp | 4 +- .../emplace_initializer_list.pass.cpp | 18 ++-- utils/libcxx/test/config.py | 6 +- 33 files changed, 262 insertions(+), 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3bd533396b..ef1726b78d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,21 +120,19 @@ if (LIBCXX_CXX_ABI STREQUAL "default") ${LLVM_MAIN_SRC_DIR}/runtimes/libcxxabi/include NO_DEFAULT_PATH ) - if ((NOT LIBCXX_STANDALONE_BUILD OR HAVE_LIBCXXABI) AND - IS_DIRECTORY "${LIBCXX_LIBCXXABI_INCLUDES_INTERNAL}") + if (LIBCXX_TARGETING_MSVC) + # FIXME: Figure out how to configure the ABI library on Windows. + set(LIBCXX_CXX_ABI_LIBNAME "vcruntime") + elseif ((NOT LIBCXX_STANDALONE_BUILD OR HAVE_LIBCXXABI) AND + IS_DIRECTORY "${LIBCXX_LIBCXXABI_INCLUDES_INTERNAL}") set(LIBCXX_CXX_ABI_LIBNAME "libcxxabi") set(LIBCXX_CXX_ABI_INCLUDE_PATHS "${LIBCXX_LIBCXXABI_INCLUDES_INTERNAL}") set(LIBCXX_CXX_ABI_INTREE 1) + elseif (APPLE) + set(LIBCXX_CXX_ABI_LIBNAME "libcxxabi") + set(LIBCXX_CXX_ABI_SYSTEM 1) else() - if (LIBCXX_TARGETING_MSVC) - # FIXME: Figure out how to configure the ABI library on Windows. - set(LIBCXX_CXX_ABI_LIBNAME "vcruntime") - elseif(APPLE) - set(LIBCXX_CXX_ABI_LIBNAME "libcxxabi") - set(LIBCXX_CXX_ABI_SYSTEM 1) - else() - set(LIBCXX_CXX_ABI_LIBNAME "default") - endif() + set(LIBCXX_CXX_ABI_LIBNAME "default") endif() else() set(LIBCXX_CXX_ABI_LIBNAME "${LIBCXX_CXX_ABI}") diff --git a/include/atomic b/include/atomic index a17bdce1cc6..f55e28ff5e9 100644 --- a/include/atomic +++ b/include/atomic @@ -861,16 +861,29 @@ kill_dependency(_Tp __y) _NOEXCEPT return __y; } -#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE -#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE -#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE -#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE -#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE -#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE -#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE -#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE -#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE -#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE +#if defined(__CLANG_ATOMIC_BOOL_LOCK_FREE) +# define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE +# define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE +# define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE +# define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE +# define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE +# define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE +# define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE +# define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE +# define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE +# define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE +#else +# define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE +# define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +# define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE +# define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE +# define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE +# define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE +# define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE +# define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE +# define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE +# define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE +#endif // general atomic diff --git a/include/math.h b/include/math.h index 79ebf2f119d..8c30ba85d22 100644 --- a/include/math.h +++ b/include/math.h @@ -307,6 +307,7 @@ long double truncl(long double x); extern "C++" { #include +#include // signbit @@ -324,22 +325,50 @@ __libcpp_signbit(_A1 __lcpp_x) _NOEXCEPT template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::value, bool>::type +typename std::enable_if::value, bool>::type signbit(_A1 __lcpp_x) _NOEXCEPT { return __libcpp_signbit((typename std::__promote<_A1>::type)__lcpp_x); } +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if< + std::is_integral<_A1>::value && std::is_signed<_A1>::value, bool>::type +signbit(_A1 __lcpp_x) _NOEXCEPT +{ return __lcpp_x < 0; } + +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if< + std::is_integral<_A1>::value && !std::is_signed<_A1>::value, bool>::type +signbit(_A1) _NOEXCEPT +{ return false; } + #elif defined(_LIBCPP_MSVCRT) template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::value, bool>::type +typename std::enable_if::value, bool>::type signbit(_A1 __lcpp_x) _NOEXCEPT { return ::signbit(static_cast::type>(__lcpp_x)); } +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if< + std::is_integral<_A1>::value && std::is_signed<_A1>::value, bool>::type +signbit(_A1 __lcpp_x) _NOEXCEPT +{ return __lcpp_x < 0; } + +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if< + std::is_integral<_A1>::value && !std::is_signed<_A1>::value, bool>::type +signbit(_A1) _NOEXCEPT +{ return false; } + #endif // signbit // fpclassify @@ -358,22 +387,34 @@ __libcpp_fpclassify(_A1 __lcpp_x) _NOEXCEPT template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::value, int>::type +typename std::enable_if::value, int>::type fpclassify(_A1 __lcpp_x) _NOEXCEPT { return __libcpp_fpclassify((typename std::__promote<_A1>::type)__lcpp_x); } +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if::value, int>::type +fpclassify(_A1 __lcpp_x) _NOEXCEPT +{ return __lcpp_x == 0 ? FP_ZERO : FP_NORMAL; } + #elif defined(_LIBCPP_MSVCRT) template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::value, int>::type +typename std::enable_if::value, bool>::type fpclassify(_A1 __lcpp_x) _NOEXCEPT { return ::fpclassify(static_cast::type>(__lcpp_x)); } +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if::value, int>::type +fpclassify(_A1 __lcpp_x) _NOEXCEPT +{ return __lcpp_x == 0 ? FP_ZERO : FP_NORMAL; } + #endif // fpclassify // isfinite @@ -392,12 +433,22 @@ __libcpp_isfinite(_A1 __lcpp_x) _NOEXCEPT template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::value, bool>::type +typename std::enable_if< + std::is_arithmetic<_A1>::value && std::numeric_limits<_A1>::has_infinity, + bool>::type isfinite(_A1 __lcpp_x) _NOEXCEPT { return __libcpp_isfinite((typename std::__promote<_A1>::type)__lcpp_x); } +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if< + std::is_arithmetic<_A1>::value && !std::numeric_limits<_A1>::has_infinity, + bool>::type +isfinite(_A1) _NOEXCEPT +{ return true; } + #endif // isfinite // isinf @@ -416,12 +467,22 @@ __libcpp_isinf(_A1 __lcpp_x) _NOEXCEPT template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::value, bool>::type +typename std::enable_if< + std::is_arithmetic<_A1>::value && std::numeric_limits<_A1>::has_infinity, + bool>::type isinf(_A1 __lcpp_x) _NOEXCEPT { return __libcpp_isinf((typename std::__promote<_A1>::type)__lcpp_x); } +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if< + std::is_arithmetic<_A1>::value && !std::numeric_limits<_A1>::has_infinity, + bool>::type +isinf(_A1) _NOEXCEPT +{ return false; } + #endif // isinf // isnan @@ -440,12 +501,18 @@ __libcpp_isnan(_A1 __lcpp_x) _NOEXCEPT template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::value, bool>::type +typename std::enable_if::value, bool>::type isnan(_A1 __lcpp_x) _NOEXCEPT { return __libcpp_isnan((typename std::__promote<_A1>::type)__lcpp_x); } +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if::value, bool>::type +isnan(_A1) _NOEXCEPT +{ return false; } + #endif // isnan // isnormal @@ -464,12 +531,18 @@ __libcpp_isnormal(_A1 __lcpp_x) _NOEXCEPT template inline _LIBCPP_INLINE_VISIBILITY -typename std::enable_if::value, bool>::type +typename std::enable_if::value, bool>::type isnormal(_A1 __lcpp_x) _NOEXCEPT { return __libcpp_isnormal((typename std::__promote<_A1>::type)__lcpp_x); } +template +inline _LIBCPP_INLINE_VISIBILITY +typename std::enable_if::value, bool>::type +isnormal(_A1 __lcpp_x) _NOEXCEPT +{ return __lcpp_x != 0; } + #endif // isnormal // isgreater diff --git a/include/mutex b/include/mutex index e92baa51ae7..0b25614e8ea 100644 --- a/include/mutex +++ b/include/mutex @@ -685,7 +685,7 @@ inline _LIBCPP_INLINE_VISIBILITY void call_once(once_flag& __flag, const _Callable& __func) { - if (__flag.__state_ != ~0ul) + if (__libcpp_acquire_load(&__flag.__state_) != ~0ul) { __call_once_param __p(__func); __call_once(__flag.__state_, &__p, &__call_once_proxy); diff --git a/test/libcxx/atomics/diagnose_invalid_memory_order.fail.cpp b/test/libcxx/atomics/diagnose_invalid_memory_order.fail.cpp index d8bb363d86b..51a1f2307ac 100644 --- a/test/libcxx/atomics/diagnose_invalid_memory_order.fail.cpp +++ b/test/libcxx/atomics/diagnose_invalid_memory_order.fail.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// This test fails because diagnose_if doesn't emit all of the diagnostics +// when -fdelayed-template-parsing is enabled, like it is on Windows. +// XFAIL: LIBCXX-WINDOWS-FIXME + // REQUIRES: verify-support, diagnose-if-support // UNSUPPORTED: libcpp-has-no-threads diff --git a/test/libcxx/language.support/support.dynamic/new_faligned_allocation.sh.cpp b/test/libcxx/language.support/support.dynamic/new_faligned_allocation.sh.cpp index 04b40009cda..8c17aabd640 100644 --- a/test/libcxx/language.support/support.dynamic/new_faligned_allocation.sh.cpp +++ b/test/libcxx/language.support/support.dynamic/new_faligned_allocation.sh.cpp @@ -10,6 +10,10 @@ // test libc++'s implementation of align_val_t, and the relevent new/delete // overloads in all dialects when -faligned-allocation is present. +// Libc++ defers to the underlying MSVC library to provide the new/delete +// definitions, which does not yet provide aligned allocation +// XFAIL: LIBCXX-WINDOWS-FIXME + // REQUIRES: -faligned-allocation // RUN: %build -faligned-allocation @@ -74,4 +78,4 @@ int main() { assert(typeid(std::align_val_t).name() == std::string("St11align_val_t")); } #endif -} \ No newline at end of file +} diff --git a/test/libcxx/localization/locales/locale.convenience/conversions/conversions.string/ctor_move.pass.cpp b/test/libcxx/localization/locales/locale.convenience/conversions/conversions.string/ctor_move.pass.cpp index 9ba422fc0c9..18cc0ca9716 100644 --- a/test/libcxx/localization/locales/locale.convenience/conversions/conversions.string/ctor_move.pass.cpp +++ b/test/libcxx/localization/locales/locale.convenience/conversions/conversions.string/ctor_move.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// 'do_bytes' throws a std::range_error unexpectedly +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: c++98, c++03 // diff --git a/test/libcxx/modules/cinttypes_exports.sh.cpp b/test/libcxx/modules/cinttypes_exports.sh.cpp index 99d20ec6502..ce39ceea44d 100644 --- a/test/libcxx/modules/cinttypes_exports.sh.cpp +++ b/test/libcxx/modules/cinttypes_exports.sh.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// This test fails on Windows because the underlying libc headers on Windows +// are not modular +// XFAIL: LIBCXX-WINDOWS-FIXME + // REQUIRES: modules-support // Test that re-exports diff --git a/test/libcxx/modules/clocale_exports.sh.cpp b/test/libcxx/modules/clocale_exports.sh.cpp index 69b1a9bd662..aacddd2d857 100644 --- a/test/libcxx/modules/clocale_exports.sh.cpp +++ b/test/libcxx/modules/clocale_exports.sh.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// This test fails on Windows because the underlying libc headers on Windows +// are not modular +// XFAIL: LIBCXX-WINDOWS-FIXME + // REQUIRES: modules-support // UNSUPPORTED: c++98, c++03 diff --git a/test/libcxx/modules/cstdint_exports.sh.cpp b/test/libcxx/modules/cstdint_exports.sh.cpp index 8ecc1da28f1..3d3cbe33817 100644 --- a/test/libcxx/modules/cstdint_exports.sh.cpp +++ b/test/libcxx/modules/cstdint_exports.sh.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// This test fails on Windows because the underlying libc headers on Windows +// are not modular +// XFAIL: LIBCXX-WINDOWS-FIXME + // REQUIRES: modules-support // Test that re-exports diff --git a/test/libcxx/modules/inttypes_h_exports.sh.cpp b/test/libcxx/modules/inttypes_h_exports.sh.cpp index d1598d7eab3..5354c8fef33 100644 --- a/test/libcxx/modules/inttypes_h_exports.sh.cpp +++ b/test/libcxx/modules/inttypes_h_exports.sh.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// This test fails on Windows because the underlying libc headers on Windows +// are not modular +// XFAIL: LIBCXX-WINDOWS-FIXME + // REQUIRES: modules-support // Test that intypes.h re-exports stdint.h diff --git a/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp b/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp index bf567a30243..12c0a3d5ef4 100644 --- a/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp +++ b/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// // +// This test depends on std::exception_ptr which has not yet been implemented. +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-no-exceptions // UNSUPPORTED: libcpp-has-no-threads // UNSUPPORTED: c++98, c++03 diff --git a/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp b/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp index 1cb61d9af29..713f4716c76 100644 --- a/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp +++ b/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp @@ -6,7 +6,9 @@ // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// + +// This test depends on std::exception_ptr which has not yet been implemented. +// XFAIL: LIBCXX-WINDOWS-FIXME // UNSUPPORTED: libcpp-no-exceptions // UNSUPPORTED: libcpp-has-no-threads diff --git a/test/libcxx/thread/thread.mutex/thread_safety_lock_guard.pass.cpp b/test/libcxx/thread/thread.mutex/thread_safety_lock_guard.pass.cpp index bff682ec4e0..6024d997843 100644 --- a/test/libcxx/thread/thread.mutex/thread_safety_lock_guard.pass.cpp +++ b/test/libcxx/thread/thread.mutex/thread_safety_lock_guard.pass.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// On Windows Clang bugs out when both __declspec and __attribute__ are present, +// the processing goes awry preventing the definition of the types. +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-has-no-threads // REQUIRES: thread-safety diff --git a/test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.pass.cpp b/test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.pass.cpp index 3898d08d837..3ada120cb9d 100644 --- a/test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.pass.cpp +++ b/test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.pass.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// On Windows Clang bugs out when both __declspec and __attribute__ are present, +// the processing goes awry preventing the definition of the types. +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-has-no-threads // REQUIRES: thread-safety diff --git a/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp b/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp index 941e9ff8f67..cf3e6384790 100644 --- a/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp +++ b/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// On Windows Clang bugs out when both __declspec and __attribute__ are present, +// the processing goes awry preventing the definition of the types. +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-has-no-threads // REQUIRES: thread-safety diff --git a/test/libcxx/thread/thread.mutex/thread_safety_requires_capability.pass.cpp b/test/libcxx/thread/thread.mutex/thread_safety_requires_capability.pass.cpp index 1a5685e8deb..e0681048d30 100644 --- a/test/libcxx/thread/thread.mutex/thread_safety_requires_capability.pass.cpp +++ b/test/libcxx/thread/thread.mutex/thread_safety_requires_capability.pass.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +// On Windows Clang bugs out when both __declspec and __attribute__ are present, +// the processing goes awry preventing the definition of the types. +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-has-no-threads // REQUIRES: thread-safety diff --git a/test/std/language.support/support.exception/except.nested/assign.pass.cpp b/test/std/language.support/support.exception/except.nested/assign.pass.cpp index 6338c8aaa26..ec5575d072c 100644 --- a/test/std/language.support/support.exception/except.nested/assign.pass.cpp +++ b/test/std/language.support/support.exception/except.nested/assign.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // // class nested_exception; diff --git a/test/std/language.support/support.exception/except.nested/ctor_copy.pass.cpp b/test/std/language.support/support.exception/except.nested/ctor_copy.pass.cpp index 4cbdbb2ec89..92134c993af 100644 --- a/test/std/language.support/support.exception/except.nested/ctor_copy.pass.cpp +++ b/test/std/language.support/support.exception/except.nested/ctor_copy.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // // class nested_exception; diff --git a/test/std/language.support/support.exception/except.nested/ctor_default.pass.cpp b/test/std/language.support/support.exception/except.nested/ctor_default.pass.cpp index 18ca9968ff5..8f8503b254d 100644 --- a/test/std/language.support/support.exception/except.nested/ctor_default.pass.cpp +++ b/test/std/language.support/support.exception/except.nested/ctor_default.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // // class nested_exception; diff --git a/test/std/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp b/test/std/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp index 68cd85038b2..fe9cd6042ba 100644 --- a/test/std/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp +++ b/test/std/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-no-exceptions // @@ -43,7 +46,7 @@ class C { public: virtual ~C() {} - C * operator&() const { assert(false); } // should not be called + C * operator&() const { assert(false); return nullptr; } // should not be called }; class D : private std::nested_exception {}; diff --git a/test/std/language.support/support.exception/except.nested/rethrow_nested.pass.cpp b/test/std/language.support/support.exception/except.nested/rethrow_nested.pass.cpp index d511a72f9f5..73d02da3933 100644 --- a/test/std/language.support/support.exception/except.nested/rethrow_nested.pass.cpp +++ b/test/std/language.support/support.exception/except.nested/rethrow_nested.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-no-exceptions // diff --git a/test/std/language.support/support.exception/except.nested/throw_with_nested.pass.cpp b/test/std/language.support/support.exception/except.nested/throw_with_nested.pass.cpp index 6a9f25cd085..6353afcb239 100644 --- a/test/std/language.support/support.exception/except.nested/throw_with_nested.pass.cpp +++ b/test/std/language.support/support.exception/except.nested/throw_with_nested.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-no-exceptions // diff --git a/test/std/language.support/support.exception/propagation/current_exception.pass.cpp b/test/std/language.support/support.exception/propagation/current_exception.pass.cpp index 661f789fefd..2046997774a 100644 --- a/test/std/language.support/support.exception/propagation/current_exception.pass.cpp +++ b/test/std/language.support/support.exception/propagation/current_exception.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-no-exceptions // diff --git a/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp b/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp index 3aa8dcf55bb..9621a736036 100644 --- a/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp +++ b/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // // typedef unspecified exception_ptr; diff --git a/test/std/language.support/support.exception/propagation/make_exception_ptr.pass.cpp b/test/std/language.support/support.exception/propagation/make_exception_ptr.pass.cpp index 36feda7304b..4980c656b2b 100644 --- a/test/std/language.support/support.exception/propagation/make_exception_ptr.pass.cpp +++ b/test/std/language.support/support.exception/propagation/make_exception_ptr.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-no-exceptions // diff --git a/test/std/language.support/support.exception/propagation/rethrow_exception.pass.cpp b/test/std/language.support/support.exception/propagation/rethrow_exception.pass.cpp index 565166cbdf7..7d27eee6689 100644 --- a/test/std/language.support/support.exception/propagation/rethrow_exception.pass.cpp +++ b/test/std/language.support/support.exception/propagation/rethrow_exception.pass.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +// exception_ptr has not been implemented on Windows +// XFAIL: LIBCXX-WINDOWS-FIXME + // UNSUPPORTED: libcpp-no-exceptions // diff --git a/test/std/numerics/c.math/cmath.pass.cpp b/test/std/numerics/c.math/cmath.pass.cpp index 7161bd37e3e..b5f586492bd 100644 --- a/test/std/numerics/c.math/cmath.pass.cpp +++ b/test/std/numerics/c.math/cmath.pass.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -551,6 +552,13 @@ void test_signbit() static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); assert(std::signbit(-1.0) == true); + assert(std::signbit(0u) == false); + assert(std::signbit(std::numeric_limits::max()) == false); + assert(std::signbit(0) == false); + assert(std::signbit(1) == false); + assert(std::signbit(-1) == true); + assert(std::signbit(std::numeric_limits::max()) == false); + assert(std::signbit(std::numeric_limits::min()) == true); } void test_fpclassify() @@ -564,6 +572,11 @@ void test_fpclassify() static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); assert(std::fpclassify(-1.0) == FP_NORMAL); + assert(std::fpclassify(0) == FP_ZERO); + assert(std::fpclassify(1) == FP_NORMAL); + assert(std::fpclassify(-1) == FP_NORMAL); + assert(std::fpclassify(std::numeric_limits::max()) == FP_NORMAL); + assert(std::fpclassify(std::numeric_limits::min()) == FP_NORMAL); } void test_isfinite() @@ -577,6 +590,11 @@ void test_isfinite() static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); assert(std::isfinite(-1.0) == true); + assert(std::isfinite(0) == true); + assert(std::isfinite(1) == true); + assert(std::isfinite(-1) == true); + assert(std::isfinite(std::numeric_limits::max()) == true); + assert(std::isfinite(std::numeric_limits::min()) == true); } void test_isnormal() @@ -590,6 +608,11 @@ void test_isnormal() static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); assert(std::isnormal(-1.0) == true); + assert(std::isnormal(0) == false); + assert(std::isnormal(1) == true); + assert(std::isnormal(-1) == true); + assert(std::isnormal(std::numeric_limits::max()) == true); + assert(std::isnormal(std::numeric_limits::min()) == true); } void test_isgreater() @@ -651,6 +674,11 @@ void test_isinf() static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); assert(std::isinf(-1.0) == false); + assert(std::isinf(0) == false); + assert(std::isinf(1) == false); + assert(std::isinf(-1) == false); + assert(std::isinf(std::numeric_limits::max()) == false); + assert(std::isinf(std::numeric_limits::min()) == false); } void test_isless() @@ -731,6 +759,11 @@ void test_isnan() static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); assert(std::isnan(-1.0) == false); + assert(std::isnan(0) == false); + assert(std::isnan(1) == false); + assert(std::isnan(-1) == false); + assert(std::isnan(std::numeric_limits::max()) == false); + assert(std::isnan(std::numeric_limits::min()) == false); } void test_isunordered() diff --git a/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp b/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp index 312e4d27fef..c8d14a1d0dd 100644 --- a/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp +++ b/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp @@ -63,7 +63,6 @@ void test(SV sv, unsigned pos, unsigned n, const typename S::allocator_type& a) { typedef typename S::traits_type T; - typedef typename S::allocator_type A; if (pos <= sv.size()) { S s2(sv, pos, n, a); diff --git a/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp b/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp index 75dfb0a2e70..7ed6121e530 100644 --- a/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp +++ b/test/std/utilities/any/any.class/any.modifiers/emplace.pass.cpp @@ -44,7 +44,7 @@ void test_emplace_type() { auto &v = a.emplace(); static_assert( std::is_same_v, "" ); - assert(&v == std::any_cast(&a)); + assert(&v == std::any_cast(&a)); assert(Tracked::count == 0); assert(Type::count == 1); @@ -60,7 +60,7 @@ void test_emplace_type() { auto &v = a.emplace(101); static_assert( std::is_same_v, "" ); - assert(&v == std::any_cast(&a)); + assert(&v == std::any_cast(&a)); assert(Tracked::count == 0); assert(Type::count == 1); @@ -76,7 +76,7 @@ void test_emplace_type() { auto &v = a.emplace(-1, 42, -1); static_assert( std::is_same_v, "" ); - assert(&v == std::any_cast(&a)); + assert(&v == std::any_cast(&a)); assert(Tracked::count == 0); assert(Type::count == 1); @@ -97,7 +97,7 @@ void test_emplace_type_tracked() { assert(Tracked::count == 1); auto &v = a.emplace(); static_assert( std::is_same_v, "" ); - assert(&v == std::any_cast(&a)); + assert(&v == std::any_cast(&a)); assert(Tracked::count == 0); assertArgsMatch(a); @@ -107,7 +107,7 @@ void test_emplace_type_tracked() { assert(Tracked::count == 1); auto &v = a.emplace(-1, 42, -1); static_assert( std::is_same_v, "" ); - assert(&v == std::any_cast(&a)); + assert(&v == std::any_cast(&a)); assert(Tracked::count == 0); assertArgsMatch(a); @@ -118,7 +118,7 @@ void test_emplace_type_tracked() { assert(Tracked::count == 1); auto &v = a.emplace({-1, 42, -1}); static_assert( std::is_same_v, "" ); - assert(&v == std::any_cast(&a)); + assert(&v == std::any_cast(&a)); assert(Tracked::count == 0); assertArgsMatch>(a); @@ -129,7 +129,7 @@ void test_emplace_type_tracked() { assert(Tracked::count == 1); auto &v = a.emplace({-1, 42, -1}, x); static_assert( std::is_same_v, "" ); - assert(&v == std::any_cast(&a)); + assert(&v == std::any_cast(&a)); assert(Tracked::count == 0); assertArgsMatch, int&>(a); @@ -159,7 +159,8 @@ void test_emplace_throws() std::any a(small{42}); assert(small::count == 1); try { - a.emplace(101); + auto &v = a.emplace(101); + static_assert( std::is_same_v, "" ); assert(false); } catch (int const&) { } @@ -169,7 +170,8 @@ void test_emplace_throws() std::any a(small{42}); assert(small::count == 1); try { - a.emplace({1, 2, 3}, 101); + auto &v = a.emplace({1, 2, 3}, 101); + static_assert( std::is_same_v, "" ); assert(false); } catch (int const&) { } @@ -180,7 +182,8 @@ void test_emplace_throws() std::any a(large{42}); assert(large::count == 1); try { - a.emplace(101); + auto &v = a.emplace(101); + static_assert( std::is_same_v, "" ); assert(false); } catch (int const&) { } @@ -190,7 +193,8 @@ void test_emplace_throws() std::any a(large{42}); assert(large::count == 1); try { - a.emplace({1, 2, 3}, 101); + auto &v = a.emplace({1, 2, 3}, 101); + static_assert( std::is_same_v, "" ); assert(false); } catch (int const&) { } diff --git a/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp b/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp index 0696c11526d..e7f59f1a94c 100644 --- a/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp +++ b/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp @@ -254,7 +254,9 @@ int main() { assert(static_cast(opt) == true); assert(Y::dtor_called == false); - opt.emplace(1); + auto &v = opt.emplace(1); + static_assert( std::is_same_v, "" ); + assert(false); } catch (int i) { diff --git a/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp b/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp index 1c3c69a7030..f6959c7e9cf 100644 --- a/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp +++ b/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp @@ -11,7 +11,7 @@ // // template -// void optional::emplace(initializer_list il, Args&&... args); +// T& optional::emplace(initializer_list il, Args&&... args); #include #include @@ -76,21 +76,27 @@ int main() X x; optional opt(x); assert(X::dtor_called == false); - opt.emplace({1, 2}); + auto &v = opt.emplace({1, 2}); + static_assert( std::is_same_v, "" ); assert(X::dtor_called == true); assert(*opt == X({1, 2})); + assert(&v == &*opt); } { optional> opt; - opt.emplace({1, 2, 3}, std::allocator()); + auto &v = opt.emplace({1, 2, 3}, std::allocator()); + static_assert( std::is_same_v&, decltype(v)>, "" ); assert(static_cast(opt) == true); assert(*opt == std::vector({1, 2, 3})); + assert(&v == &*opt); } { optional opt; - opt.emplace({1, 2}); + auto &v = opt.emplace({1, 2}); + static_assert( std::is_same_v, "" ); assert(static_cast(opt) == true); assert(*opt == Y({1, 2})); + assert(&v == &*opt); } #ifndef TEST_HAS_NO_EXCEPTIONS { @@ -100,7 +106,9 @@ int main() { assert(static_cast(opt) == true); assert(Z::dtor_called == false); - opt.emplace({1, 2}); + auto &v = opt.emplace({1, 2}); + static_assert( std::is_same_v, "" ); + assert(false); } catch (int i) { diff --git a/utils/libcxx/test/config.py b/utils/libcxx/test/config.py index bd99e8ddd97..f839a3a0985 100644 --- a/utils/libcxx/test/config.py +++ b/utils/libcxx/test/config.py @@ -311,10 +311,10 @@ class Configuration(object): # NOTE: We do not test for the -verify flag directly because # -verify will always exit with non-zero on an empty file. self.use_clang_verify = self.cxx.isVerifySupported() - if self.use_clang_verify: - self.config.available_features.add('verify-support') self.lit_config.note( "inferred use_clang_verify as: %r" % self.use_clang_verify) + if self.use_clang_verify: + self.config.available_features.add('verify-support') def configure_use_thread_safety(self): '''If set, run clang with -verify on failing tests.''' @@ -418,7 +418,7 @@ class Configuration(object): # initial Windows failures until they can be properly diagnosed # and fixed. This allows easier detection of new test failures # and regressions. Note: New failures should not be suppressed - # using this feature. + # using this feature. (Also see llvm.org/PR32730) self.config.available_features.add('LIBCXX-WINDOWS-FIXME') # Attempt to detect the glibc version by querying for __GLIBC__ From e06a19b85dfce9ea18be97247d4ca315963edc5c Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 26 Apr 2017 19:24:42 +0000 Subject: [PATCH 03/10] Vendor import of lld trunk r301441: https://llvm.org/svn/llvm-project/lld/trunk@301441 --- COFF/Chunks.cpp | 44 +++++++++++++- COFF/Config.h | 1 + COFF/Driver.cpp | 17 ++++++ COFF/Driver.h | 2 +- COFF/DriverUtils.cpp | 27 +++++---- COFF/InputFiles.h | 3 +- COFF/Librarian.cpp | 20 ++++--- COFF/ModuleDef.cpp | 7 +++ COFF/SymbolTable.h | 5 -- ELF/Driver.cpp | 73 ++++++++++++++-------- ELF/Filesystem.cpp | 17 +++--- ELF/Filesystem.h | 2 +- ELF/InputFiles.cpp | 42 ++++++++----- ELF/InputFiles.h | 12 ++-- ELF/Options.td | 2 + ELF/OutputSections.cpp | 6 +- ELF/SymbolTable.cpp | 34 +++++++++-- ELF/SymbolTable.h | 1 + ELF/Symbols.cpp | 3 +- ELF/SyntheticSections.cpp | 4 +- ELF/Target.cpp | 17 +----- ELF/Writer.cpp | 7 +-- test/COFF/Inputs/constant-export.ll | 10 ++++ test/COFF/Inputs/msvclto-order-a.ll | 7 +++ test/COFF/Inputs/msvclto-order-b.ll | 10 ++++ test/COFF/constant-export.test | 9 +++ test/COFF/constant-export.yaml | 83 ++++++++++++++++++++++++++ test/COFF/linkenv.test | 4 +- test/COFF/msvclto-order.ll | 24 ++++++++ test/ELF/Inputs/progname-ver.s | 3 + test/ELF/Inputs/progname-ver.so | Bin 1680 -> 0 bytes test/ELF/defsym.s | 44 ++++++++++++++ test/ELF/driver-access.test | 14 +++++ test/ELF/icf-i386.s | 25 ++++++++ test/ELF/incompatible-section-flags.s | 9 ++- test/ELF/linkerscript/sections.s | 14 ++--- test/ELF/lto/asmundef.ll | 3 +- test/ELF/progname.s | 30 ++++------ test/ELF/tls-dynamic-i686.s | 6 +- 39 files changed, 488 insertions(+), 153 deletions(-) create mode 100644 test/COFF/Inputs/constant-export.ll create mode 100644 test/COFF/Inputs/msvclto-order-a.ll create mode 100644 test/COFF/Inputs/msvclto-order-b.ll create mode 100644 test/COFF/constant-export.test create mode 100644 test/COFF/constant-export.yaml create mode 100644 test/COFF/msvclto-order.ll create mode 100644 test/ELF/Inputs/progname-ver.s delete mode 100755 test/ELF/Inputs/progname-ver.so create mode 100644 test/ELF/defsym.s create mode 100644 test/ELF/driver-access.test create mode 100644 test/ELF/icf-i386.s diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 10eeedd88e5..2e49f417a20 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -319,8 +319,48 @@ void SEHTableChunk::writeTo(uint8_t *Buf) const { std::sort(Begin, Begin + Cnt); } -// Windows-specific. -// This class represents a block in .reloc section. +// Windows-specific. This class represents a block in .reloc section. +// The format is described here. +// +// On Windows, each DLL is linked against a fixed base address and +// usually loaded to that address. However, if there's already another +// DLL that overlaps, the loader has to relocate it. To do that, DLLs +// contain .reloc sections which contain offsets that need to be fixed +// up at runtime. If the loader find that a DLL cannot be loaded to its +// desired base address, it loads it to somewhere else, and add - to each offset that is +// specified by .reloc section. +// +// In ELF terms, .reloc sections contain arrays of relocation offsets. +// All these offsets in the section are implicitly R_*_RELATIVE, and +// addends are read from section contents (so it is REL as opposed to +// RELA). +// +// This already reduce the size of relocations to 1/3 compared to ELF +// .dynrel, but Windows does more to reduce it (probably because it was +// invented for PCs in the late '80s or early '90s.) Offsets in .reloc +// are grouped by page where page size is 16 bits, and offsets sharing +// the same page address are stored consecutively to represent them with +// less space. This is a very similar to the page table which is grouped +// by (multiple stages of) pages. +// +// For example, let's say we have 0x00030, 0x00500, 0x01000, 0x01100, +// 0x20004, and 0x20008 in a .reloc section. In the section, they are +// represented like this: +// +// 0x00000 -- page address (4 bytes) +// 16 -- size of this block (4 bytes) +// 0x0030 -- entries (2 bytes each) +// 0x0500 +// 0x1000 +// 0x1100 +// 0x20000 -- page address (4 bytes) +// 12 -- size of this block (4 bytes) +// 0x0004 -- entries (2 bytes each) +// 0x0008 +// +// Usually we have a lot of relocatinos for each page, so the number of +// bytes for one .reloc entry is close to 2 bytes. BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { // Block header consists of 4 byte page RVA and 4 byte block size. // Each entry is 2 byte. Last entry may be padding. diff --git a/COFF/Config.h b/COFF/Config.h index 31534aeb397..fafd3bcde2e 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -43,6 +43,7 @@ struct Export { bool Noname = false; bool Data = false; bool Private = false; + bool Constant = false; // If an export is a form of /export:foo=dllname.bar, that means // that foo should be exported as an alias to bar in the DLL. diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index daddfb86d4c..5a15b5b1150 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -512,6 +512,23 @@ void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { std::string Rsp = "/nologo\n"; std::vector Temps; + // Write out archive members that we used in symbol resolution and pass these + // to MSVC before any archives, so that MSVC uses the same objects to satisfy + // references. + for (const auto *O : Symtab.ObjectFiles) { + if (O->ParentName.empty()) + continue; + SmallString<128> S; + int Fd; + if (auto EC = sys::fs::createTemporaryFile( + "lld-" + sys::path::filename(O->ParentName), ".obj", Fd, S)) + fatal(EC, "cannot create a temporary file"); + raw_fd_ostream OS(Fd, /*shouldClose*/ true); + OS << O->MB.getBuffer(); + Temps.push_back(S.str()); + Rsp += quote(S) + "\n"; + } + for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_linkrepro: diff --git a/COFF/Driver.h b/COFF/Driver.h index 4566f73eef3..ad725625e03 100644 --- a/COFF/Driver.h +++ b/COFF/Driver.h @@ -48,7 +48,7 @@ public: llvm::opt::InputArgList parse(llvm::ArrayRef Args); // Concatenate LINK environment varirable and given arguments and parse them. - llvm::opt::InputArgList parseLINK(llvm::ArrayRef Args); + llvm::opt::InputArgList parseLINK(std::vector Args); // Tokenizes a given string and then parses as command line options. llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index 2c9ba797f73..252590c7d87 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -479,6 +479,10 @@ Export parseExport(StringRef Arg) { E.Data = true; continue; } + if (Tok.equals_lower("constant")) { + E.Constant = true; + continue; + } if (Tok.equals_lower("private")) { E.Private = true; continue; @@ -695,17 +699,20 @@ opt::InputArgList ArgParser::parse(ArrayRef ArgsArr) { return Args; } -// link.exe has an interesting feature. If LINK environment exists, -// its contents are handled as a command line string. So you can pass -// extra arguments using the environment variable. -opt::InputArgList ArgParser::parseLINK(ArrayRef Args) { +// link.exe has an interesting feature. If LINK or _LINK_ environment +// variables exist, their contents are handled as command line strings. +// So you can pass extra arguments using them. +opt::InputArgList ArgParser::parseLINK(std::vector Args) { // Concatenate LINK env and command line arguments, and then parse them. - Optional Env = Process::GetEnv("LINK"); - if (!Env) - return parse(Args); - std::vector V = tokenize(*Env); - V.insert(V.end(), Args.begin(), Args.end()); - return parse(V); + if (Optional S = Process::GetEnv("LINK")) { + std::vector V = tokenize(*S); + Args.insert(Args.begin(), V.begin(), V.end()); + } + if (Optional S = Process::GetEnv("_LINK_")) { + std::vector V = tokenize(*S); + Args.insert(Args.begin(), V.begin(), V.end()); + } + return parse(Args); } std::vector ArgParser::tokenize(StringRef S) { diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index 9e02b2fc68b..3078de68752 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -58,6 +58,8 @@ public: // Returns the CPU type this file was compiled to. virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } + MemoryBufferRef MB; + // An archive file name if this file is created from an archive. StringRef ParentName; @@ -67,7 +69,6 @@ public: protected: InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} - MemoryBufferRef MB; std::string Directives; private: diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp index 3ce72822180..91316ee6b0c 100644 --- a/COFF/Librarian.cpp +++ b/COFF/Librarian.cpp @@ -162,7 +162,7 @@ public: // Create a short import file which is described in PE/COFF spec 7. Import // Library Format. NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, - ImportNameType NameType, bool isData); + ImportType Type, ImportNameType NameType); }; } @@ -440,8 +440,8 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector &Buffer) { NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal, - ImportNameType NameType, - bool isData) { + ImportType ImportType, + ImportNameType NameType) { size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs size_t Size = sizeof(coff_import_header) + ImpSize; char *Buf = Alloc.Allocate(Size); @@ -456,8 +456,7 @@ NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, Imp->SizeOfData = ImpSize; if (Ordinal > 0) Imp->OrdinalHint = Ordinal; - Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE); - Imp->TypeInfo |= NameType << 2; + Imp->TypeInfo = (NameType << 2) | ImportType; // Write symbol name and DLL name. memcpy(P, Sym.data(), Sym.size()); @@ -490,11 +489,18 @@ void lld::coff::writeImportLibrary() { if (E.Private) continue; - ImportNameType Type = getNameType(E.SymbolName, E.Name); + ImportType ImportType = IMPORT_CODE; + if (E.Data) + ImportType = IMPORT_DATA; + if (E.Constant) + ImportType = IMPORT_CONST; + + ImportNameType NameType = getNameType(E.SymbolName, E.Name); std::string Name = E.ExtName.empty() ? std::string(E.SymbolName) : replace(E.SymbolName, E.Name, E.ExtName); - Members.push_back(OF.createShortImport(Name, E.Ordinal, Type, E.Data)); + Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, + NameType)); } std::pair Result = diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp index c9a40ac5ab8..740ce867a7c 100644 --- a/COFF/ModuleDef.cpp +++ b/COFF/ModuleDef.cpp @@ -38,6 +38,7 @@ enum Kind { Comma, Equal, KwBase, + KwConstant, KwData, KwExports, KwHeapsize, @@ -92,6 +93,7 @@ public: StringRef Word = Buf.substr(0, End); Kind K = llvm::StringSwitch(Word) .Case("BASE", KwBase) + .Case("CONSTANT", KwConstant) .Case("DATA", KwData) .Case("EXPORTS", KwExports) .Case("HEAPSIZE", KwHeapsize) @@ -227,6 +229,11 @@ private: E.Data = true; continue; } + if (Tok.K == KwConstant) { + warn("CONSTANT keyword is obsolete; use DATA"); + E.Constant = true; + continue; + } if (Tok.K == KwPrivate) { E.Private = true; continue; diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h index 764dd531877..bf8d6618d96 100644 --- a/COFF/SymbolTable.h +++ b/COFF/SymbolTable.h @@ -108,14 +108,9 @@ public: std::vector LocalImportChunks; private: - void readArchive(); - void readObjects(); - std::pair insert(StringRef Name); StringRef findByPrefix(StringRef Prefix); - void addCombinedLTOObject(ObjectFile *Obj); - llvm::DenseMap Symtab; std::vector BitcodeFiles; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 93924e4554c..68eb5616a5c 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -184,8 +184,6 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { error("attempted static link of dynamic object " + Path); return; } - Files.push_back(createSharedFile(MBRef)); - // DSOs usually have DT_SONAME tags in their ELF headers, and the // sonames are used to identify DSOs. But if they are missing, // they are identified by filenames. We don't know whether the new @@ -196,8 +194,8 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { // If a file was specified by -lfoo, the directory part is not // significant, as a user did not specify it. This behavior is // compatible with GNU. - Files.back()->DefaultSoName = - WithLOption ? sys::path::filename(Path) : Path; + Files.push_back(createSharedFile( + MBRef, WithLOption ? sys::path::filename(Path) : Path)); return; default: if (InLib) @@ -708,10 +706,6 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); - for (auto *Arg : Args.filtered(OPT_dynamic_list)) - if (Optional Buffer = readFile(Arg->getValue())) - readDynamicList(*Buffer); - if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) if (Optional Buffer = readFile(Arg->getValue())) Config->SymbolOrderingFile = getLines(*Buffer); @@ -726,22 +720,32 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { {S, /*IsExternCpp*/ false, /*HasWildcard*/ false}); } - for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) - Config->VersionScriptGlobals.push_back( - {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); + bool HasExportDynamic = + getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false); - // Dynamic lists are a simplified linker script that doesn't need the - // "global:" and implicitly ends with a "local:*". Set the variables needed to - // simulate that. - if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) { - Config->ExportDynamic = true; - if (!Config->Shared) - Config->DefaultSymbolVersion = VER_NDX_LOCAL; + // Parses -dynamic-list and -export-dynamic-symbol. They make some + // symbols private. Note that -export-dynamic takes precedence over them + // as it says all symbols should be exported. + if (!HasExportDynamic) { + for (auto *Arg : Args.filtered(OPT_dynamic_list)) + if (Optional Buffer = readFile(Arg->getValue())) + readDynamicList(*Buffer); + + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) + Config->VersionScriptGlobals.push_back( + {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); + + // Dynamic lists are a simplified linker script that doesn't need the + // "global:" and implicitly ends with a "local:*". Set the variables + // needed to simulate that. + if (Args.hasArg(OPT_dynamic_list) || + Args.hasArg(OPT_export_dynamic_symbol)) { + Config->ExportDynamic = true; + if (!Config->Shared) + Config->DefaultSymbolVersion = VER_NDX_LOCAL; + } } - if (getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false)) - Config->DefaultSymbolVersion = VER_NDX_GLOBAL; - if (auto *Arg = Args.getLastArg(OPT_version_script)) if (Optional Buffer = readFile(Arg->getValue())) readVersionScript(*Buffer); @@ -876,6 +880,21 @@ static uint64_t getImageBase(opt::InputArgList &Args) { return V; } +// Parses --defsym=alias option. +static std::vector> +getDefsym(opt::InputArgList &Args) { + std::vector> Ret; + for (auto *Arg : Args.filtered(OPT_defsym)) { + StringRef From; + StringRef To; + std::tie(From, To) = StringRef(Arg->getValue()).split('='); + if (!isValidCIdentifier(To)) + error("--defsym: symbol name expected, but got " + To); + Ret.push_back({From, To}); + } + return Ret; +} + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template void LinkerDriver::link(opt::InputArgList &Args) { @@ -893,9 +912,11 @@ template void LinkerDriver::link(opt::InputArgList &Args) { // Fail early if the output file or map file is not writable. If a user has a // long link, e.g. due to a large LTO link, they do not wish to run it and // find that it failed because there was a mistake in their command-line. - if (!isFileWritable(Config->OutputFile, "output file")) - return; - if (!isFileWritable(Config->MapFile, "map file")) + if (auto E = tryCreateFile(Config->OutputFile)) + error("cannot open output file " + Config->OutputFile + ": " + E.message()); + if (auto E = tryCreateFile(Config->MapFile)) + error("cannot open map file " + Config->MapFile + ": " + E.message()); + if (ErrorCount) return; // Use default entry point name if no name was given via the command @@ -941,6 +962,10 @@ template void LinkerDriver::link(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_wrap)) Symtab.wrap(Arg->getValue()); + // Handle --defsym=sym=alias option. + for (std::pair &Def : getDefsym(Args)) + Symtab.alias(Def.first, Def.second); + // Now that we have a complete list of input files. // Beyond this point, no new files are added. // Aggregate all input sections into one place. diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp index 75f7bda75a2..b63d521a83b 100644 --- a/ELF/Filesystem.cpp +++ b/ELF/Filesystem.cpp @@ -13,7 +13,6 @@ #include "Filesystem.h" #include "Config.h" -#include "Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileOutputBuffer.h" #include @@ -58,22 +57,20 @@ void elf::unlinkAsync(StringRef Path) { std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); } -// Returns true if a given file seems to be writable. +// Simulate file creation to see if Path is writable. // // Determining whether a file is writable or not is amazingly hard, // and after all the only reliable way of doing that is to actually // create a file. But we don't want to do that in this function // because LLD shouldn't update any file if it will end in a failure. -// We also don't want to reimplement heuristics. So we'll let -// FileOutputBuffer do the work. +// We also don't want to reimplement heuristics to determine if a +// file is writable. So we'll let FileOutputBuffer do the work. // // FileOutputBuffer doesn't touch a desitnation file until commit() // is called. We use that class without calling commit() to predict // if the given file is writable. -bool elf::isFileWritable(StringRef Path, StringRef Desc) { - if (auto EC = FileOutputBuffer::create(Path, 1).getError()) { - error("cannot open " + Desc + " " + Path + ": " + EC.message()); - return false; - } - return true; +std::error_code elf::tryCreateFile(StringRef Path) { + if (Path.empty()) + return std::error_code(); + return FileOutputBuffer::create(Path, 1).getError(); } diff --git a/ELF/Filesystem.h b/ELF/Filesystem.h index a33dc3651a4..d56d067f737 100644 --- a/ELF/Filesystem.h +++ b/ELF/Filesystem.h @@ -15,7 +15,7 @@ namespace lld { namespace elf { void unlinkAsync(StringRef Path); -bool isFileWritable(StringRef Path, StringRef FileDescription); +std::error_code tryCreateFile(StringRef Path); } } diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index d651fbcad25..d99f71eb4aa 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -608,8 +608,9 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { } template -SharedFile::SharedFile(MemoryBufferRef M) - : ELFFileBase(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {} +SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) + : ELFFileBase(Base::SharedKind, M), SoName(DefaultSoName), + AsNeeded(Config->AsNeeded) {} template const typename ELFT::Shdr * @@ -619,12 +620,6 @@ SharedFile::getSection(const Elf_Sym &Sym) const { toString(this)); } -template StringRef SharedFile::getSoName() const { - if (SoName.empty()) - return this->DefaultSoName; - return SoName; -} - // Partially parse the shared object file so that we can call // getSoName on this object. template void SharedFile::parseSoName() { @@ -867,8 +862,23 @@ void BitcodeFile::parse(DenseSet &ComdatGroups) { Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, this)); } +// Small bit of template meta programming to handle the SharedFile constructor +// being the only one with a DefaultSoName parameter. +template