From b138afd1f457f16c9dbe7587e0b5ba25415972c2 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 6 Jun 2025 14:08:59 +0100 Subject: [PATCH 01/16] Target: Add target option for disabling `AArch64_ELFTargetObjectFile::SupportIndirectSymViaGOTPCRel` The Swift compiler needs to disable this option in order for the standard library to link successfully on Linux. See: - https://github.com/swiftlang/llvm-project/pull/9339 - https://github.com/llvm/llvm-project/pull/78003 --- llvm/include/llvm/Target/TargetOptions.h | 5 +++++ llvm/lib/Target/AArch64/AArch64TargetMachine.cpp | 8 +++++--- llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp | 1 - llvm/lib/Target/AArch64/AArch64TargetObjectFile.h | 4 ++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h index 77a461e0aaee4..61fb82d295260 100644 --- a/llvm/include/llvm/Target/TargetOptions.h +++ b/llvm/include/llvm/Target/TargetOptions.h @@ -140,6 +140,7 @@ class TargetOptions { XRayFunctionIndex(true), DebugStrictDwarf(false), Hotpatch(false), PPCGenScalarMASSEntries(false), JMCInstrument(false), EnableCFIFixup(false), MisExpect(false), XCOFFReadOnlyPointers(false), + SupportIndirectSymViaGOTPCRel_AArch64_ELF(true), VerifyArgABICompliance(true), FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {} @@ -375,6 +376,10 @@ class TargetOptions { /// into the RO data section. unsigned XCOFFReadOnlyPointers : 1; + /// When set to true, enables indirect symbol replacement with GOTPCREL for + /// AArch64/ELF. The default is `true`. + unsigned SupportIndirectSymViaGOTPCRel_AArch64_ELF : 1; + /// When set to true, call/return argument extensions of narrow integers /// are verified in the target backend if it cares about them. This is /// not done with internal tools like llc that run many tests that ignore diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp index 95eab16511e5a..0a7b1f14fff75 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -280,13 +280,15 @@ void AArch64TargetMachine::reset() { SubtargetMap.clear(); } //===----------------------------------------------------------------------===// // AArch64 Lowering public interface. //===----------------------------------------------------------------------===// -static std::unique_ptr createTLOF(const Triple &TT) { +static std::unique_ptr +createTLOF(const Triple &TT, const TargetOptions &Options) { if (TT.isOSBinFormatMachO()) return std::make_unique(); if (TT.isOSBinFormatCOFF()) return std::make_unique(); - return std::make_unique(); + return std::make_unique( + Options.SupportIndirectSymViaGOTPCRel_AArch64_ELF); } // Helper function to build a DataLayout string @@ -367,7 +369,7 @@ AArch64TargetMachine::AArch64TargetMachine(const Target &T, const Triple &TT, computeDefaultCPU(TT, CPU), FS, Options, getEffectiveRelocModel(TT, RM), getEffectiveAArch64CodeModel(TT, CM, JIT), OL), - TLOF(createTLOF(getTargetTriple())), isLittle(LittleEndian) { + TLOF(createTLOF(getTargetTriple(), Options)), isLittle(LittleEndian) { initAsmInfo(); if (TT.isOSBinFormatMachO()) { diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp index 61864306b57de..1091f84f7fb30 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp @@ -27,7 +27,6 @@ void AArch64_ELFTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM) { TargetLoweringObjectFileELF::Initialize(Ctx, TM); PLTRelativeSpecifier = AArch64::S_PLT; - SupportIndirectSymViaGOTPCRel = true; // AARCH64 ELF ABI does not define static relocation type for TLS offset // within a module. Do not generate AT_location for TLS variables. diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h index 01700e98ce3bd..aeee7a1937706 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h +++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h @@ -20,6 +20,10 @@ class AArch64_ELFTargetObjectFile : public TargetLoweringObjectFileELF { void Initialize(MCContext &Ctx, const TargetMachine &TM) override; public: + AArch64_ELFTargetObjectFile(bool SupportIndirectSymViaGOTPCRel) { + this->SupportIndirectSymViaGOTPCRel = SupportIndirectSymViaGOTPCRel; + } + const MCExpr *getIndirectSymViaGOTPCRel(const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, int64_t Offset, From 6c1b359fc3c9fc23fb81f714babe48433eee55fb Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Thu, 12 Jun 2025 01:46:27 +0100 Subject: [PATCH 02/16] Revert "[clang] Remove unused CodeGen:: ptrauth helpers. NFCI." This reverts commit 6fe29b94f0b9eb79c853ff0549f68125027e3b6b. --- clang/include/clang/CodeGen/CodeGenABITypes.h | 14 ++++++++++++++ clang/lib/CodeGen/CGPointerAuth.cpp | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h index 1df379d54c382..51fbbbfae1b8f 100644 --- a/clang/include/clang/CodeGen/CodeGenABITypes.h +++ b/clang/include/clang/CodeGen/CodeGenABITypes.h @@ -120,6 +120,20 @@ llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T); unsigned getLLVMFieldNumber(CodeGenModule &CGM, const RecordDecl *RD, const FieldDecl *FD); +/// Return a declaration discriminator for the given global decl. +uint16_t getPointerAuthDeclDiscriminator(CodeGenModule &CGM, GlobalDecl GD); + +/// Return a type discriminator for the given function type. +uint16_t getPointerAuthTypeDiscriminator(CodeGenModule &CGM, + QualType FunctionType); + +/// Return a signed constant pointer. +llvm::Constant *getConstantSignedPointer(CodeGenModule &CGM, + llvm::Constant *pointer, + unsigned key, + llvm::Constant *storageAddress, + llvm::ConstantInt *otherDiscriminator); + /// Given the language and code-generation options that Clang was configured /// with, set the default LLVM IR attributes for a function definition. /// The attributes set here are mostly global target-configuration and diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index fbea607b409fd..952c884c86357 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -53,6 +53,16 @@ llvm::ConstantInt *CodeGenModule::getPointerAuthOtherDiscriminator( llvm_unreachable("bad discrimination kind"); } +uint16_t CodeGen::getPointerAuthTypeDiscriminator(CodeGenModule &CGM, + QualType FunctionType) { + return CGM.getContext().getPointerAuthTypeDiscriminator(FunctionType); +} + +uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM, + GlobalDecl Declaration) { + return CGM.getPointerAuthDeclDiscriminator(Declaration); +} + /// Return the "other" decl-specific discriminator for the given decl. uint16_t CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl Declaration) { @@ -588,6 +598,15 @@ llvm::Constant *CodeGenModule::getConstantSignedPointer( OtherDiscriminator); } +llvm::Constant * +CodeGen::getConstantSignedPointer(CodeGenModule &CGM, + llvm::Constant *pointer, unsigned key, + llvm::Constant *storageAddress, + llvm::ConstantInt *otherDiscriminator) { + return CGM.getConstantSignedPointer(pointer, key, storageAddress, + otherDiscriminator); +} + void CodeGenModule::destroyConstantSignedPointerCaches() { destroyCache(ConstantSignedPointersByConstant); destroyCache(ConstantSignedPointersByDecl); From 3ed40e995539b9528cf675c08035962691deb1f7 Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Thu, 1 Aug 2024 14:23:00 -0700 Subject: [PATCH 03/16] Revert "[Hashing] get_execution_seed: use a non-vague linkage symbol" This reverts commit c00ada070207979f092be9046a02fcfff8b9f9ce. --- llvm/include/llvm/ADT/Hashing.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h index ad131015a7d99..eee77e8ea3ffd 100644 --- a/llvm/include/llvm/ADT/Hashing.h +++ b/llvm/include/llvm/ADT/Hashing.h @@ -308,13 +308,13 @@ struct hash_state { }; /// In LLVM_ENABLE_ABI_BREAKING_CHECKS builds, the seed is non-deterministic -/// per process (address of a function in LLVMSupport) to prevent having users -/// depend on the particular hash values. On platforms without ASLR, this is -/// still likely non-deterministic per build. +/// (address of a variable) to prevent having users depend on the particular +/// hash values. On platforms without ASLR, this is still likely +/// non-deterministic per build. inline uint64_t get_execution_seed() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS - return static_cast( - reinterpret_cast(&install_fatal_error_handler)); + static const char seed = 0; + return static_cast(reinterpret_cast(&seed)); #else return 0xff51afd7ed558ccdULL; #endif From a1e7036fe739927a2156bc3df22695065ffdf706 Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Thu, 1 Aug 2024 14:23:22 -0700 Subject: [PATCH 04/16] Revert "[Hashing] Use a non-deterministic seed if LLVM_ENABLE_ABI_BREAKING_CHECKS" This reverts commit ce80c80dca45c7b4636a3e143973e2c6cbdb2884. There's a number of clients in Swift (and our fork) that rely on `hash_value` being deterministic. We can add this back in after those are fixed. --- llvm/include/llvm/ADT/Hashing.h | 45 +++++++++--- llvm/lib/Support/CMakeLists.txt | 1 + llvm/lib/Support/Hashing.cpp | 28 ++++++++ llvm/unittests/ADT/HashingTest.cpp | 72 +++++++++++++++++++ .../gn/secondary/llvm/lib/Support/BUILD.gn | 1 + 5 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 llvm/lib/Support/Hashing.cpp diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h index eee77e8ea3ffd..5be75058ce99c 100644 --- a/llvm/include/llvm/ADT/Hashing.h +++ b/llvm/include/llvm/ADT/Hashing.h @@ -45,7 +45,6 @@ #define LLVM_ADT_HASHING_H #include "llvm/ADT/ADL.h" -#include "llvm/Config/abi-breaking.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SwapByteOrder.h" @@ -128,6 +127,23 @@ hash_code hash_value(const std::basic_string &arg); /// Compute a hash_code for a standard string. template hash_code hash_value(const std::optional &arg); +/// Override the execution seed with a fixed value. +/// +/// This hashing library uses a per-execution seed designed to change on each +/// run with high probability in order to ensure that the hash codes are not +/// attackable and to ensure that output which is intended to be stable does +/// not rely on the particulars of the hash codes produced. +/// +/// That said, there are use cases where it is important to be able to +/// reproduce *exactly* a specific behavior. To that end, we provide a function +/// which will forcibly set the seed to a fixed value. This must be done at the +/// start of the program, before any hashes are computed. Also, it cannot be +/// undone. This makes it thread-hostile and very hard to use outside of +/// immediately on start of a simple program designed for reproducible +/// behavior. +void set_fixed_execution_hash_seed(uint64_t fixed_value); + + // All of the implementation details of actually computing the various hash // code values are held within this namespace. These routines are included in // the header file mainly to allow inlining and constant propagation. @@ -307,17 +323,24 @@ struct hash_state { } }; -/// In LLVM_ENABLE_ABI_BREAKING_CHECKS builds, the seed is non-deterministic -/// (address of a variable) to prevent having users depend on the particular -/// hash values. On platforms without ASLR, this is still likely -/// non-deterministic per build. + +/// A global, fixed seed-override variable. +/// +/// This variable can be set using the \see llvm::set_fixed_execution_seed +/// function. See that function for details. Do not, under any circumstances, +/// set or read this variable. +extern uint64_t fixed_seed_override; + inline uint64_t get_execution_seed() { -#if LLVM_ENABLE_ABI_BREAKING_CHECKS - static const char seed = 0; - return static_cast(reinterpret_cast(&seed)); -#else - return 0xff51afd7ed558ccdULL; -#endif + // FIXME: This needs to be a per-execution seed. This is just a placeholder + // implementation. Switching to a per-execution seed is likely to flush out + // instability bugs and so will happen as its own commit. + // + // However, if there is a fixed seed override set the first time this is + // called, return that instead of the per-execution seed. + const uint64_t seed_prime = 0xff51afd7ed558ccdULL; + static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime; + return seed; } diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 13f0d51ca23a6..8878f1406817b 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -199,6 +199,7 @@ add_llvm_component_library(LLVMSupport FormatVariadic.cpp GlobPattern.cpp GraphWriter.cpp + Hashing.cpp HexagonAttributeParser.cpp HexagonAttributes.cpp InitLLVM.cpp diff --git a/llvm/lib/Support/Hashing.cpp b/llvm/lib/Support/Hashing.cpp new file mode 100644 index 0000000000000..1b20a670434f1 --- /dev/null +++ b/llvm/lib/Support/Hashing.cpp @@ -0,0 +1,28 @@ +//===-------------- lib/Support/Hashing.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides implementation bits for the LLVM common hashing +// infrastructure. Documentation and most of the other information is in the +// header file. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Hashing.h" + +using namespace llvm; + +// Provide a definition and static initializer for the fixed seed. This +// initializer should always be zero to ensure its value can never appear to be +// non-zero, even during dynamic initialization. +uint64_t llvm::hashing::detail::fixed_seed_override = 0; + +// Implement the function for forced setting of the fixed seed. +// FIXME: Use atomic operations here so that there is no data race. +void llvm::set_fixed_execution_hash_seed(uint64_t fixed_value) { + hashing::detail::fixed_seed_override = fixed_value; +} diff --git a/llvm/unittests/ADT/HashingTest.cpp b/llvm/unittests/ADT/HashingTest.cpp index e116ee934a0a4..82b85ea275da3 100644 --- a/llvm/unittests/ADT/HashingTest.cpp +++ b/llvm/unittests/ADT/HashingTest.cpp @@ -239,6 +239,78 @@ TEST(HashingTest, HashCombineRangeLengthDiff) { } } +TEST(HashingTest, HashCombineRangeGoldenTest) { + struct { const char *s; uint64_t hash; } golden_data[] = { +#if SIZE_MAX == UINT64_MAX || SIZE_MAX == UINT32_MAX + { "a", 0xaeb6f9d5517c61f8ULL }, + { "ab", 0x7ab1edb96be496b4ULL }, + { "abc", 0xe38e60bf19c71a3fULL }, + { "abcde", 0xd24461a66de97f6eULL }, + { "abcdefgh", 0x4ef872ec411dec9dULL }, + { "abcdefghijklm", 0xe8a865539f4eadfeULL }, + { "abcdefghijklmnopqrstu", 0x261cdf85faaf4e79ULL }, + { "abcdefghijklmnopqrstuvwxyzabcdef", 0x43ba70e4198e3b2aULL }, + { "abcdefghijklmnopqrstuvwxyzabcdef" + "abcdefghijklmnopqrstuvwxyzghijkl" + "abcdefghijklmnopqrstuvwxyzmnopqr" + "abcdefghijklmnopqrstuvwxyzstuvwx" + "abcdefghijklmnopqrstuvwxyzyzabcd", 0xdcd57fb2afdf72beULL }, + { "a", 0xaeb6f9d5517c61f8ULL }, + { "aa", 0xf2b3b69a9736a1ebULL }, + { "aaa", 0xf752eb6f07b1cafeULL }, + { "aaaaa", 0x812bd21e1236954cULL }, + { "aaaaaaaa", 0xff07a2cff08ac587ULL }, + { "aaaaaaaaaaaaa", 0x84ac949d54d704ecULL }, + { "aaaaaaaaaaaaaaaaaaaaa", 0xcb2c8fb6be8f5648ULL }, + { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0xcc40ab7f164091b6ULL }, + { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0xc58e174c1e78ffe9ULL }, + { "z", 0x1ba160d7e8f8785cULL }, + { "zz", 0x2c5c03172f1285d7ULL }, + { "zzz", 0x9d2c4f4b507a2ac3ULL }, + { "zzzzz", 0x0f03b9031735693aULL }, + { "zzzzzzzz", 0xe674147c8582c08eULL }, + { "zzzzzzzzzzzzz", 0x3162d9fa6938db83ULL }, + { "zzzzzzzzzzzzzzzzzzzzz", 0x37b9a549e013620cULL }, + { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0x8921470aff885016ULL }, + { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0xf60fdcd9beb08441ULL }, + { "a", 0xaeb6f9d5517c61f8ULL }, + { "ab", 0x7ab1edb96be496b4ULL }, + { "aba", 0x3edb049950884d0aULL }, + { "ababa", 0x8f2de9e73a97714bULL }, + { "abababab", 0xee14a29ddf0ce54cULL }, + { "ababababababa", 0x38b3ddaada2d52b4ULL }, + { "ababababababababababa", 0xd3665364219f2b85ULL }, + { "abababababababababababababababab", 0xa75cd6afbf1bc972ULL }, + { "abababababababababababababababab" + "abababababababababababababababab" + "abababababababababababababababab" + "abababababababababababababababab" + "abababababababababababababababab", 0x840192d129f7a22bULL } +#else +#error This test only supports 64-bit and 32-bit systems. +#endif + }; + for (unsigned i = 0; i < sizeof(golden_data)/sizeof(*golden_data); ++i) { + StringRef str = golden_data[i].s; + hash_code hash = hash_combine_range(str.begin(), str.end()); +#if 0 // Enable this to generate paste-able text for the above structure. + std::string member_str = "\"" + str.str() + "\","; + fprintf(stderr, " { %-35s 0x%016llxULL },\n", + member_str.c_str(), static_cast(hash)); +#endif + EXPECT_EQ(static_cast(golden_data[i].hash), + static_cast(hash)); + } +} + TEST(HashingTest, HashCombineBasicTest) { // Hashing a sequence of homogenous types matches range hashing. const int i1 = 42, i2 = 43, i3 = 123, i4 = 999, i5 = 0, i6 = 79; diff --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn index 0ea1c6fcee5ee..4d1d53f607634 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn @@ -95,6 +95,7 @@ static_library("Support") { "FormattedStream.cpp", "GlobPattern.cpp", "GraphWriter.cpp", + "Hashing.cpp", "HexagonAttributeParser.cpp", "HexagonAttributes.cpp", "InitLLVM.cpp", From 06f1ce41965b451bd8ac0d629f0602d2be063045 Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Tue, 3 Oct 2023 20:37:22 -0700 Subject: [PATCH 05/16] Revert "[Parse] Always end translation unit" This reverts commit 76cfe6c67efa25ab42ed34e51201c3912765195f. Only running `ActOnEndOfTranslationUnit` when `enableIncrementalProcessing` was false was the only NFC part of splitting `-fincremental-extensions` and `enableIncrementalProcessing` again (68090ee7224763bf7204de4d9f9ca7edc8203d40). LLDB started failing after that change with: ``` /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk/usr/include/c++/v1/cstdlib:127:9: error: declaration of 'calloc' must be imported from module 'Darwin.malloc._malloc' before it is required ``` Reverting that part of the change fixed LLDB and didn't cause any other test failures, so happy days. Unfortunately most of what `Sema::ActOnEndOfTranslationUnit` does is additional diagnostics, which don't make a lot of sense from the Clang Importer in Swift. So this ends up being a significant regression if eg. `-warnings-as-errors` is enabled. Resolves rdar://116194950. (cherry picked from commit eed23a111debf73c9bc53fcf0df611a7d27d12c0) --- clang/lib/Parse/Parser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 3d146f75ab57a..652ba274be221 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -722,7 +722,8 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, // Late template parsing can begin. Actions.SetLateTemplateParser(LateTemplateParserCallback, nullptr, this); - Actions.ActOnEndOfTranslationUnit(); + if (!PP.isIncrementalProcessingEnabled()) + Actions.ActOnEndOfTranslationUnit(); //else don't tell Sema that we ended parsing: more input might come. return true; From 5d5f0bddf372684efec739631bc92ca6ed410edd Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Tue, 3 Oct 2023 20:34:26 -0700 Subject: [PATCH 06/16] Revert "[lldb] Fix the way we set up the lldb modules infrastructure." This reverts commit f247725b91b8c1c07b4e50e5f006f670536fd3c7, which was a re-application of the original change added back in after "fixing" the underlying issue. See the next commit (also a revert) for more details. (cherry picked from commit 2e975208511c31c40c139a3248b732bcf0128619) --- .../Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp | 3 ++- .../lang/objc/modules-compile-error/TestModulesCompileError.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 2f838b3f095f9..cfd1e8efabf08 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -669,7 +669,6 @@ ClangModulesDeclVendor::Create(Target &target) { arch.GetTriple().str(), "-fmodules-validate-system-headers", "-Werror=non-modular-include-in-framework-module", - "-Xclang=-fincremental-extensions", "-Rmodule-build"}; target.GetPlatform()->AddClangModuleCompilationOptions( @@ -764,6 +763,8 @@ ClangModulesDeclVendor::Create(Target &target) { instance->getFrontendOpts().Inputs[0])) return nullptr; + instance->getPreprocessor().enableIncrementalProcessing(); + instance->createASTReader(); instance->createSema(action->getTranslationUnitKind(), nullptr); diff --git a/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py b/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py index 36e302be2525b..db6d74bfdb540 100644 --- a/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py +++ b/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py @@ -21,7 +21,7 @@ def test(self): "expr @import LLDBTestModule", error=True, substrs=[ - "module.h:4:1: error: use of undeclared identifier 'syntax_error_for_lldb_to_find'", + "module.h:4:1: error: unknown type name 'syntax_error_for_lldb_to_find'", "syntax_error_for_lldb_to_find // comment that tests source printing", "could not build module 'LLDBTestModule'", ], From 4013f324f67d51c277b379132e94e2e2b40bb752 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 27 Jun 2025 08:46:45 +0100 Subject: [PATCH 07/16] Revert "[libc++] Remove dead implementation of is_nothrow_convertible and merge the remaining code into is_convertible.h (#137717)" This reverts commit e43e8ec7afbdf8b90204060b725d6990829b80a1. --- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__type_traits/is_convertible.h | 10 --- .../__type_traits/is_nothrow_convertible.h | 62 +++++++++++++++++++ libcxx/include/module.modulemap.in | 4 ++ libcxx/include/type_traits | 1 + 5 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 libcxx/include/__type_traits/is_nothrow_convertible.h diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 4f2a8dddad92c..9cc1d3acc016f 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -847,6 +847,7 @@ set(files __type_traits/is_member_pointer.h __type_traits/is_nothrow_assignable.h __type_traits/is_nothrow_constructible.h + __type_traits/is_nothrow_convertible.h __type_traits/is_nothrow_destructible.h __type_traits/is_null_pointer.h __type_traits/is_object.h diff --git a/libcxx/include/__type_traits/is_convertible.h b/libcxx/include/__type_traits/is_convertible.h index f0a859f9cc16d..cef3c4a764914 100644 --- a/libcxx/include/__type_traits/is_convertible.h +++ b/libcxx/include/__type_traits/is_convertible.h @@ -26,16 +26,6 @@ template _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_convertible_v = __is_convertible(_From, _To); #endif -#if _LIBCPP_STD_VER >= 20 - -template -struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_convertible : bool_constant<__is_nothrow_convertible(_Tp, _Up)> {}; - -template -_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_convertible_v = __is_nothrow_convertible(_Tp, _Up); - -#endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TYPE_TRAITS_IS_CONVERTIBLE_H diff --git a/libcxx/include/__type_traits/is_nothrow_convertible.h b/libcxx/include/__type_traits/is_nothrow_convertible.h new file mode 100644 index 0000000000000..f114619296437 --- /dev/null +++ b/libcxx/include/__type_traits/is_nothrow_convertible.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H +#define _LIBCPP___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H + +#include <__config> +#include <__type_traits/conjunction.h> +#include <__type_traits/disjunction.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_void.h> +#include <__type_traits/lazy.h> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +# if __has_builtin(__is_nothrow_convertible) + +template +struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_convertible : bool_constant<__is_nothrow_convertible(_Tp, _Up)> {}; + +template +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_convertible_v = __is_nothrow_convertible(_Tp, _Up); + +# else // __has_builtin(__is_nothrow_convertible) + +template +void __test_noexcept(_Tp) noexcept; + +template +bool_constant(std::declval<_Fm>()))> __is_nothrow_convertible_test(); + +template +struct __is_nothrow_convertible_helper : decltype(std::__is_nothrow_convertible_test<_Fm, _To>()) {}; + +template +struct is_nothrow_convertible + : _Or<_And, is_void<_Fm>>, + _Lazy<_And, is_convertible<_Fm, _To>, __is_nothrow_convertible_helper<_Fm, _To> > >::type {}; + +template +inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<_Fm, _To>::value; + +# endif // __has_builtin(__is_nothrow_convertible) + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_NOTHROW_CONVERTIBLE_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 61ba1c381b2b3..04ef9de78604e 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -232,6 +232,10 @@ module std_core [system] { header "__type_traits/is_nothrow_constructible.h" export std_core.type_traits.integral_constant } + module is_nothrow_convertible { + header "__type_traits/is_nothrow_convertible.h" + export std_core.type_traits.integral_constant + } module is_nothrow_destructible { header "__type_traits/is_nothrow_destructible.h" export std_core.type_traits.integral_constant diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index a6e0c1867566b..fa767587801e6 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -548,6 +548,7 @@ namespace std # include <__type_traits/common_reference.h> # include <__type_traits/is_bounded_array.h> # include <__type_traits/is_constant_evaluated.h> +# include <__type_traits/is_nothrow_convertible.h> # include <__type_traits/is_unbounded_array.h> # include <__type_traits/type_identity.h> # include <__type_traits/unwrap_ref.h> From 77f8d272a04edbdb04cfc78bfc1e218d22451da8 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 27 Jun 2025 09:12:39 +0100 Subject: [PATCH 08/16] Revert "[libc++] Remove a few unused includes from <__bit/*> (#137934)" This partially reverts commit a6459debc06f9cb86940ff5cdae35a1f52e1ed19. --- libcxx/include/__bit/countl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__bit/countl.h b/libcxx/include/__bit/countl.h index 075914020879a..5326c65770692 100644 --- a/libcxx/include/__bit/countl.h +++ b/libcxx/include/__bit/countl.h @@ -9,6 +9,7 @@ #ifndef _LIBCPP___BIT_COUNTL_H #define _LIBCPP___BIT_COUNTL_H +#include <__bit/rotate.h> #include <__config> #include <__type_traits/integer_traits.h> #include From 92a6898b63cfa6cf3cf92df7fed452ff450acecf Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 27 Jun 2025 09:13:58 +0100 Subject: [PATCH 09/16] Revert "[libc++] Replace __libcpp_{ctz, clz} with __builtin_{ctzg, clzg} (#133920)" This reverts commit 9e3982d9ae8173171cd7247ee505e9c02079c6bf. --- libcxx/include/__algorithm/sort.h | 12 ++-- libcxx/include/__bit/countl.h | 62 +++++++++++++++++++ libcxx/include/__bit/countr.h | 52 +++++++++++++++- libcxx/include/__bit_reference | 4 +- libcxx/include/__charconv/to_chars_integral.h | 15 +++-- libcxx/include/__charconv/traits.h | 21 +++++-- libcxx/include/__hash_table | 2 +- 7 files changed, 146 insertions(+), 22 deletions(-) diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h index 06cb5b8ce7057..d7bc1381ba5e1 100644 --- a/libcxx/include/__algorithm/sort.h +++ b/libcxx/include/__algorithm/sort.h @@ -359,10 +359,10 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos( // Swap one pair on each iteration as long as both bitsets have at least one // element for swapping. while (__left_bitset != 0 && __right_bitset != 0) { - difference_type __tz_left = std::__countr_zero(__left_bitset); - __left_bitset = std::__libcpp_blsr(__left_bitset); - difference_type __tz_right = std::__countr_zero(__right_bitset); - __right_bitset = std::__libcpp_blsr(__right_bitset); + difference_type __tz_left = __libcpp_ctz(__left_bitset); + __left_bitset = __libcpp_blsr(__left_bitset); + difference_type __tz_right = __libcpp_ctz(__right_bitset); + __right_bitset = __libcpp_blsr(__right_bitset); _Ops::iter_swap(__first + __tz_left, __last - __tz_right); } } @@ -458,7 +458,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within( // Swap within the left side. Need to find set positions in the reverse // order. while (__left_bitset != 0) { - difference_type __tz_left = __detail::__block_size - 1 - std::__countl_zero(__left_bitset); + difference_type __tz_left = __detail::__block_size - 1 - __libcpp_clz(__left_bitset); __left_bitset &= (static_cast(1) << __tz_left) - 1; _RandomAccessIterator __it = __first + __tz_left; if (__it != __lm1) { @@ -471,7 +471,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within( // Swap within the right side. Need to find set positions in the reverse // order. while (__right_bitset != 0) { - difference_type __tz_right = __detail::__block_size - 1 - std::__countl_zero(__right_bitset); + difference_type __tz_right = __detail::__block_size - 1 - __libcpp_clz(__right_bitset); __right_bitset &= (static_cast(1) << __tz_right) - 1; _RandomAccessIterator __it = __lm1 - __tz_right; if (__it != __first) { diff --git a/libcxx/include/__bit/countl.h b/libcxx/include/__bit/countl.h index 5326c65770692..33083cca2eb36 100644 --- a/libcxx/include/__bit/countl.h +++ b/libcxx/include/__bit/countl.h @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +// TODO: __builtin_clzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_clzg. + #ifndef _LIBCPP___BIT_COUNTL_H #define _LIBCPP___BIT_COUNTL_H @@ -23,10 +26,69 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned __x) _NOEXCEPT { + return __builtin_clz(__x); +} + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned long __x) _NOEXCEPT { + return __builtin_clzl(__x); +} + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned long long __x) _NOEXCEPT { + return __builtin_clzll(__x); +} + +#if _LIBCPP_HAS_INT128 +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(__uint128_t __x) _NOEXCEPT { +# if __has_builtin(__builtin_clzg) + return __builtin_clzg(__x); +# else + // The function is written in this form due to C++ constexpr limitations. + // The algorithm: + // - Test whether any bit in the high 64-bits is set + // - No bits set: + // - The high 64-bits contain 64 leading zeros, + // - Add the result of the low 64-bits. + // - Any bits set: + // - The number of leading zeros of the input is the number of leading + // zeros in the high 64-bits. + return ((__x >> 64) == 0) ? (64 + __builtin_clzll(static_cast(__x))) + : __builtin_clzll(static_cast(__x >> 64)); +# endif +} +#endif // _LIBCPP_HAS_INT128 + template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _NOEXCEPT { static_assert(__is_unsigned_integer_v<_Tp>, "__countl_zero requires an unsigned integer type"); +#if __has_builtin(__builtin_clzg) return __builtin_clzg(__t, numeric_limits<_Tp>::digits); +#else // __has_builtin(__builtin_clzg) + if (__t == 0) + return numeric_limits<_Tp>::digits; + + if (sizeof(_Tp) <= sizeof(unsigned int)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else if (sizeof(_Tp) <= sizeof(unsigned long)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else if (sizeof(_Tp) <= sizeof(unsigned long long)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else { + int __ret = 0; + int __iter = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (true) { + __t = std::__rotl(__t, __ulldigits); + if ((__iter = std::__countl_zero(static_cast(__t))) != __ulldigits) + break; + __ret += __iter; + } + return __ret + __iter; + } +#endif // __has_builtin(__builtin_clzg) } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h index f6c98695d3d06..f1cede786034f 100644 --- a/libcxx/include/__bit/countr.h +++ b/libcxx/include/__bit/countr.h @@ -6,11 +6,16 @@ // //===----------------------------------------------------------------------===// +// TODO: __builtin_ctzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_ctzg. + #ifndef _LIBCPP___BIT_COUNTR_H #define _LIBCPP___BIT_COUNTR_H +#include <__bit/rotate.h> #include <__config> #include <__type_traits/integer_traits.h> +#include <__type_traits/is_unsigned.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -22,10 +27,55 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned __x) _NOEXCEPT { + return __builtin_ctz(__x); +} + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned long __x) _NOEXCEPT { + return __builtin_ctzl(__x); +} + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned long long __x) _NOEXCEPT { + return __builtin_ctzll(__x); +} + +// A constexpr implementation for C++11 and later (using clang extensions for constexpr support) +// Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case) +template +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL(__t != 0, "__countr_zero_impl called with zero value"); + static_assert(is_unsigned<_Tp>::value, "__countr_zero_impl only works with unsigned types"); + if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned int)) { + return std::__libcpp_ctz(static_cast(__t)); + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long)) { + return std::__libcpp_ctz(static_cast(__t)); + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long long)) { + return std::__libcpp_ctz(static_cast(__t)); + } else { +#if _LIBCPP_STD_VER == 11 + unsigned long long __ull = static_cast(__t); + const unsigned int __ulldigits = numeric_limits::digits; + return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz(__ull); +#else + int __ret = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (static_cast(__t) == 0uLL) { + __ret += __ulldigits; + __t >>= __ulldigits; + } + return __ret + std::__libcpp_ctz(static_cast(__t)); +#endif + } +} + template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { - static_assert(__is_unsigned_integer_v<_Tp>, "__countr_zero only works with unsigned types"); + static_assert(is_unsigned<_Tp>::value, "__countr_zero only works with unsigned types"); +#if __has_builtin(__builtin_ctzg) // TODO (LLVM 21): This can be dropped once we only support Clang >= 19. return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); +#else + return __t != 0 ? std::__countr_zero_impl(__t) : numeric_limits<_Tp>::digits; +#endif } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index a3e6defd405f8..552e0f5e4d799 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -165,7 +165,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void flip() _NOEXCEPT { *__seg_ ^= __mask_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> operator&() const _NOEXCEPT { - return __bit_iterator<_Cp, false>(__seg_, static_cast(std::__countr_zero(__mask_))); + return __bit_iterator<_Cp, false>(__seg_, static_cast(std::__libcpp_ctz(__mask_))); } private: @@ -234,7 +234,7 @@ public: } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, true> operator&() const _NOEXCEPT { - return __bit_iterator<_Cp, true>(__seg_, static_cast(std::__countr_zero(__mask_))); + return __bit_iterator<_Cp, true>(__seg_, static_cast(std::__libcpp_ctz(__mask_))); } private: diff --git a/libcxx/include/__charconv/to_chars_integral.h b/libcxx/include/__charconv/to_chars_integral.h index f10cc3566875a..238c96d7c7a04 100644 --- a/libcxx/include/__charconv/to_chars_integral.h +++ b/libcxx/include/__charconv/to_chars_integral.h @@ -114,8 +114,9 @@ struct _LIBCPP_HIDDEN __integral<2> { template _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int __width(_Tp __value) _NOEXCEPT { // If value == 0 still need one digit. If the value != this has no - // effect since the code scans for the most significant bit set. - return numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1); + // effect since the code scans for the most significant bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1); } template @@ -149,8 +150,9 @@ struct _LIBCPP_HIDDEN __integral<8> { template _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int __width(_Tp __value) _NOEXCEPT { // If value == 0 still need one digit. If the value != this has no - // effect since the code scans for the most significat bit set. - return ((numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1)) + 2) / 3; + // effect since the code scans for the most significat bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return ((numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1)) + 2) / 3; } template @@ -184,8 +186,9 @@ struct _LIBCPP_HIDDEN __integral<16> { template _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int __width(_Tp __value) _NOEXCEPT { // If value == 0 still need one digit. If the value != this has no - // effect since the code scans for the most significat bit set. - return (numeric_limits<_Tp>::digits - std::__countl_zero(__value | 1) + 3) / 4; + // effect since the code scans for the most significat bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return (numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1) + 3) / 4; } template diff --git a/libcxx/include/__charconv/traits.h b/libcxx/include/__charconv/traits.h index 9fd0092ca79c3..085a3f7886f31 100644 --- a/libcxx/include/__charconv/traits.h +++ b/libcxx/include/__charconv/traits.h @@ -43,9 +43,12 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t(__v | 1))) * 1233 >> 12; + auto __t = (32 - std::__libcpp_clz(static_cast(__v | 1))) * 1233 >> 12; return __t - (__v < __itoa::__pow10_32[__t]) + 1; } @@ -66,9 +69,12 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t(__v | 1))) * 1233 >> 12; + auto __t = (64 - std::__libcpp_clz(static_cast(__v | 1))) * 1233 >> 12; return __t - (__v < __itoa::__pow10_64[__t]) + 1; } @@ -90,12 +96,15 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t numeric_limits::max(), "The optimizations for this algorithm fail when this isn't true."); // There's always a bit set in the upper 64-bits. - auto __t = (128 - std::__countl_zero(static_cast(__v >> 64))) * 1233 >> 12; + auto __t = (128 - std::__libcpp_clz(static_cast(__v >> 64))) * 1233 >> 12; _LIBCPP_ASSERT_INTERNAL(__t >= __itoa::__pow10_128_offset, "Index out of bounds"); // __t is adjusted since the lookup table misses the lower entries. return __t - (__v < __itoa::__pow10_128[__t - __itoa::__pow10_128_offset]) + 1; diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index 78f2f3bfd2f4c..e42a148241972 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -163,7 +163,7 @@ inline _LIBCPP_HIDE_FROM_ABI size_t __constrain_hash(size_t __h, size_t __bc) { } inline _LIBCPP_HIDE_FROM_ABI size_t __next_hash_pow2(size_t __n) { - return __n < 2 ? __n : (size_t(1) << (numeric_limits::digits - std::__countl_zero(__n - 1))); + return __n < 2 ? __n : (size_t(1) << (numeric_limits::digits - __libcpp_clz(__n - 1))); } template From 2c220d8ca4f935c2901e0c09832174ae0cce8d51 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 27 Jun 2025 09:18:34 +0100 Subject: [PATCH 10/16] Revert "[libc++] Replace __libcpp_popcount by __builtin_popcountg (#133937)" This reverts commit 703cfe745b96751c1204bcffe4e56038c809247f. --- libcxx/include/__bit/popcount.h | 45 ++++++++++++++++++- .../include/__stop_token/atomic_unique_lock.h | 2 +- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__bit/popcount.h b/libcxx/include/__bit/popcount.h index 8d9ba09938482..5dbe934022e4e 100644 --- a/libcxx/include/__bit/popcount.h +++ b/libcxx/include/__bit/popcount.h @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +// TODO: __builtin_popcountg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_popcountg. + #ifndef _LIBCPP___BIT_POPCOUNT_H #define _LIBCPP___BIT_POPCOUNT_H @@ -21,10 +24,50 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned __x) _NOEXCEPT { + return __builtin_popcount(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned long __x) _NOEXCEPT { + return __builtin_popcountl(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned long long __x) _NOEXCEPT { + return __builtin_popcountll(__x); +} + +template +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount_impl(_Tp __t) _NOEXCEPT { + if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned int)) { + return std::__libcpp_popcount(static_cast(__t)); + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long)) { + return std::__libcpp_popcount(static_cast(__t)); + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) <= sizeof(unsigned long long)) { + return std::__libcpp_popcount(static_cast(__t)); + } else { +#if _LIBCPP_STD_VER == 11 + return __t != 0 ? std::__libcpp_popcount(static_cast(__t)) + + std::__popcount_impl<_Tp>(__t >> numeric_limits::digits) + : 0; +#else + int __ret = 0; + while (__t != 0) { + __ret += std::__libcpp_popcount(static_cast(__t)); + __t >>= std::numeric_limits::digits; + } + return __ret; +#endif + } +} + template [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount(_Tp __t) _NOEXCEPT { - static_assert(__is_unsigned_integer_v<_Tp>, "__popcount only works with unsigned types"); + static_assert(is_unsigned<_Tp>::value, "__popcount only works with unsigned types"); +#if __has_builtin(__builtin_popcountg) // TODO (LLVM 21): This can be dropped once we only support Clang >= 19. return __builtin_popcountg(__t); +#else + return std::__popcount_impl(__t); +#endif } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__stop_token/atomic_unique_lock.h b/libcxx/include/__stop_token/atomic_unique_lock.h index 05e8f223167f1..a698260ac7bbd 100644 --- a/libcxx/include/__stop_token/atomic_unique_lock.h +++ b/libcxx/include/__stop_token/atomic_unique_lock.h @@ -28,7 +28,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD // and LockedBit is the value of State when the lock bit is set, e.g 1 << 2 template class _LIBCPP_AVAILABILITY_SYNC __atomic_unique_lock { - static_assert(std::__popcount(static_cast(_LockedBit)) == 1, + static_assert(std::__libcpp_popcount(static_cast(_LockedBit)) == 1, "LockedBit must be an integer where only one bit is set"); std::atomic<_State>& __state_; From 1e1c7014cda908e70087bf7ce169cd86687577bc Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 25 Apr 2025 18:34:19 +0100 Subject: [PATCH 11/16] Revert "[clang] Remove dead incremental Parser code (#102450)" This reverts commit 67cb04035fe831a3b5df98dabc44b53ba5ff7126. When importing headers, the Swift ClangImporter library depends on `clang::Parser::ParseTopLevelDecl` consuming an EOF token when `IncrementalProcessing` is set. --- clang/lib/Parse/Parser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 652ba274be221..764c4e182d25a 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -629,6 +629,11 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, Sema::ModuleImportState &ImportState) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this); + // Skip over the EOF token, flagging end of previous input for incremental + // processing + if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) + ConsumeToken(); + Result = nullptr; switch (Tok.getKind()) { case tok::annot_pragma_unused: From 58307d98d962b542bdd8f18c956be13901b707e0 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 9 Jul 2025 08:29:30 +0100 Subject: [PATCH 12/16] Revert "[Clang][Sema] Allow qualified type names in `swift_name` attribute" (cherry picked from commit b6b282b3d586dd54e66830426a39fdfe92c35504) --- clang/lib/Sema/SemaSwift.cpp | 17 +++------ clang/test/SemaObjCXX/attr-swift_name-cxx.mm | 36 -------------------- 2 files changed, 4 insertions(+), 49 deletions(-) diff --git a/clang/lib/Sema/SemaSwift.cpp b/clang/lib/Sema/SemaSwift.cpp index 1a1f11112f8d2..8bc97a950d8ac 100644 --- a/clang/lib/Sema/SemaSwift.cpp +++ b/clang/lib/Sema/SemaSwift.cpp @@ -72,15 +72,6 @@ static bool isValidSwiftErrorResultType(QualType Ty) { return isValidSwiftContextType(Ty); } -static bool isValidSwiftContextName(StringRef ContextName) { - // ContextName might be qualified, e.g. 'MyNamespace.MyStruct'. - SmallVector ContextNameComponents; - ContextName.split(ContextNameComponents, '.'); - return all_of(ContextNameComponents, [&](StringRef Component) { - return isValidAsciiIdentifier(Component); - }); -} - void SemaSwift::handleAttrAttr(Decl *D, const ParsedAttr &AL) { if (AL.isInvalid() || AL.isUsedAsTypeAttr()) return; @@ -365,11 +356,11 @@ static bool validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, // Split at the first '.', if it exists, which separates the context name // from the base name. - std::tie(ContextName, BaseName) = BaseName.rsplit('.'); + std::tie(ContextName, BaseName) = BaseName.split('.'); if (BaseName.empty()) { BaseName = ContextName; ContextName = StringRef(); - } else if (ContextName.empty() || !isValidSwiftContextName(ContextName)) { + } else if (ContextName.empty() || !isValidAsciiIdentifier(ContextName)) { S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL << /*context*/ 1; return false; @@ -593,11 +584,11 @@ bool SemaSwift::DiagnoseName(Decl *D, StringRef Name, SourceLocation Loc, !IsAsync) { StringRef ContextName, BaseName; - std::tie(ContextName, BaseName) = Name.rsplit('.'); + std::tie(ContextName, BaseName) = Name.split('.'); if (BaseName.empty()) { BaseName = ContextName; ContextName = StringRef(); - } else if (!isValidSwiftContextName(ContextName)) { + } else if (!isValidAsciiIdentifier(ContextName)) { Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL << /*context*/ 1; return false; diff --git a/clang/test/SemaObjCXX/attr-swift_name-cxx.mm b/clang/test/SemaObjCXX/attr-swift_name-cxx.mm index 9e83c63ecf2f8..658dbfff185ca 100644 --- a/clang/test/SemaObjCXX/attr-swift_name-cxx.mm +++ b/clang/test/SemaObjCXX/attr-swift_name-cxx.mm @@ -1,43 +1,7 @@ // RUN: %clang_cc1 -verify -fsyntax-only -fobjc-arc -fblocks %s -#define SWIFT_NAME(name) __attribute__((swift_name(name))) #define SWIFT_ASYNC_NAME(name) __attribute__((__swift_async_name__(name))) -namespace MyNS { -struct NestedStruct {}; -} - -void nestedStruct_method(MyNS::NestedStruct) SWIFT_NAME("MyNS.NestedStruct.method(self:)"); -void nestedStruct_methodConstRef(const MyNS::NestedStruct&) SWIFT_NAME("MyNS.NestedStruct.methodConstRef(self:)"); -void nestedStruct_invalidContext1(MyNS::NestedStruct) SWIFT_NAME(".MyNS.NestedStruct.invalidContext1(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}} -void nestedStruct_invalidContext2(MyNS::NestedStruct) SWIFT_NAME("MyNS::NestedStruct.invalidContext2(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}} -void nestedStruct_invalidContext3(MyNS::NestedStruct) SWIFT_NAME("::MyNS::NestedStruct.invalidContext3(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}} -void nestedStruct_invalidContext4(MyNS::NestedStruct) SWIFT_NAME("MyNS..NestedStruct.invalidContext4(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}} -void nestedStruct_invalidContext5(MyNS::NestedStruct) SWIFT_NAME("MyNS.NestedStruct.invalidContext5.(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the base name}} -void nestedStruct_invalidContext6(MyNS::NestedStruct) SWIFT_NAME("MyNS.NestedStruct::invalidContext6(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the base name}} - -namespace MyNS { -namespace MyDeepNS { -struct DeepNestedStruct {}; -} -} - -void deepNestedStruct_method(MyNS::MyDeepNS::DeepNestedStruct) SWIFT_NAME("MyNS.MyDeepNS.DeepNestedStruct.method(self:)"); -void deepNestedStruct_methodConstRef(const MyNS::MyDeepNS::DeepNestedStruct&) SWIFT_NAME("MyNS.MyDeepNS.DeepNestedStruct.methodConstRef(self:)"); -void deepNestedStruct_invalidContext(const MyNS::MyDeepNS::DeepNestedStruct&) SWIFT_NAME("MyNS::MyDeepNS::DeepNestedStruct.methodConstRef(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}} - -typedef MyNS::MyDeepNS::DeepNestedStruct DeepNestedStructTypedef; - -void deepNestedStructTypedef_method(DeepNestedStructTypedef) SWIFT_NAME("DeepNestedStructTypedef.method(self:)"); -void deepNestedStructTypedef_methodQualName(MyNS::MyDeepNS::DeepNestedStruct) SWIFT_NAME("DeepNestedStructTypedef.method(self:)"); - -struct TopLevelStruct { - struct StructInStruct {}; -}; - -void structInStruct_method(TopLevelStruct::StructInStruct) SWIFT_NAME("TopLevelStruct.StructInStruct.method(self:)"); -void structInStruct_invalidContext(TopLevelStruct::StructInStruct) SWIFT_NAME("TopLevelStruct::StructInStruct.method(self:)"); // expected-warning {{'swift_name' attribute has invalid identifier for the context name}} - typedef int (^CallbackTy)(void); class CXXClass { From 6a9347f9e56d9af0fcd9a582bb9f316957f2f817 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Mon, 28 Aug 2023 10:10:40 -0700 Subject: [PATCH 13/16] [JITLink] Truncate ELF symbol sizes to fit containing block. LLVM currently emits dubious symbol sizes for aliases. E.g. assembling the following with LLVM top-of-tree... ``` $ cat foo.s .data .globl base base: .dword 42 .size base, 8 .set alias, base+4 ``` results in both base and alias having symbol size 8, even alias starts at base + 4. This also means that alias extends past the end of the .data section in this example. We should probably teach LLVM not to do this in the future, but as a short-term fix this patch teaches JITLink to simply truncate symbols that would extend past the end of their containing block. rdar://114207607 (cherry picked from commit 6267697a4c88688a89d2d770d00d52eab8aa72c7) Conflicts: llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h (cherry picked from commit 2f53a4c56aff5bd3a880f87fda414f5123dab6b4) --- .../ExecutionEngine/JITLink/ELFLinkGraphBuilder.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h index 8dd176cd07f92..10eafbf83fe07 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h +++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h @@ -529,6 +529,11 @@ template Error ELFLinkGraphBuilder::graphifySymbols() { return make_error(std::move(ErrMsg)); } + // Truncate symbol if it would overflow -- ELF size fields can't be + // trusted. + uint64_t Size = + std::min(static_cast(Sym.st_size), B->getSize() - Offset); + // In RISCV, temporary symbols (Used to generate dwarf, eh_frame // sections...) will appear in object code's symbol table, and LLVM does // not use names on these temporary symbols (RISCV gnu toolchain uses @@ -536,11 +541,9 @@ template Error ELFLinkGraphBuilder::graphifySymbols() { // anonymous symbol. auto &GSym = Name->empty() - ? G->addAnonymousSymbol(*B, Offset, Sym.st_size, - false, false) - : G->addDefinedSymbol(*B, Offset, *Name, Sym.st_size, L, - S, Sym.getType() == ELF::STT_FUNC, - false); + ? G->addAnonymousSymbol(*B, Offset, Size, false, false) + : G->addDefinedSymbol(*B, Offset, *Name, Size, L, S, + Sym.getType() == ELF::STT_FUNC, false); GSym.setTargetFlags(Flags); setGraphSymbol(SymIndex, GSym); From 38e0c5eba76fa9955afd5f41ccc01ea840142c58 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Wed, 21 Aug 2024 18:03:19 -0700 Subject: [PATCH 14/16] [jitlink] Fix cherry-pick in 6267697a4c This change fixed the size of the symbol but the check that emited the error was still using the old size. Updated to use the correct size, which will make the code in the if unreachable, but it's probably better to leave it to avoid merge conflicts. rdar://133510063 (cherry picked from commit d629b3871976677b908e1f240fb3691d796b708b) --- .../ExecutionEngine/JITLink/ELFLinkGraphBuilder.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h index 10eafbf83fe07..47e1b37f572f3 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h +++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h @@ -513,7 +513,14 @@ template Error ELFLinkGraphBuilder::graphifySymbols() { TargetFlagsType Flags = makeTargetFlags(Sym); orc::ExecutorAddrDiff Offset = getRawOffset(Sym, Flags); - if (Offset + Sym.st_size > B->getSize()) { + // Truncate symbol if it would overflow -- ELF size fields can't be + // trusted. + // FIXME: this makes the following error check unreachable, but it's + // left here to reduce merge conflicts. + uint64_t Size = + std::min(static_cast(Sym.st_size), B->getSize() - Offset); + + if (Offset + Size > B->getSize()) { std::string ErrMsg; raw_string_ostream ErrStream(ErrMsg); ErrStream << "In " << G->getName() << ", symbol "; @@ -529,11 +536,6 @@ template Error ELFLinkGraphBuilder::graphifySymbols() { return make_error(std::move(ErrMsg)); } - // Truncate symbol if it would overflow -- ELF size fields can't be - // trusted. - uint64_t Size = - std::min(static_cast(Sym.st_size), B->getSize() - Offset); - // In RISCV, temporary symbols (Used to generate dwarf, eh_frame // sections...) will appear in object code's symbol table, and LLVM does // not use names on these temporary symbols (RISCV gnu toolchain uses From ae0c681e659aa071617fac778c710449baafd056 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Mon, 28 Aug 2023 22:30:46 -0700 Subject: [PATCH 15/16] [JITLink] Use the union of ELF section permissions rdar://114207428. Swift is currently generating multiple .rodata sections with a combination of SHF_ALLOC and (SHF_ALLOC | SHF_WRITABLE) flags and this was tripping an assert in the ELFLinkGraphBuilder. As a temporary workaround this patch just uses the union of the requested permissions. rdar://114207428 (cherry picked from commit ead32e1f2de2dc1f35297c17a2e7911df90605b7) Conflicts: llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h (cherry picked from commit a655fbef92eed9133c66c6d6d21db5b1e5dcddcb) --- llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h index 47e1b37f572f3..8946fc31db4d8 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h +++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h @@ -375,14 +375,7 @@ template Error ELFLinkGraphBuilder::graphifySections() { } } - if (GraphSec->getMemProt() != Prot) { - std::string ErrMsg; - raw_string_ostream(ErrMsg) - << "In " << G->getName() << ", section " << *Name - << " is present more than once with different permissions: " - << GraphSec->getMemProt() << " vs " << Prot; - return make_error(std::move(ErrMsg)); - } + GraphSec->setMemProt(GraphSec->getMemProt() | Prot); Block *B = nullptr; if (Sec.sh_type != ELF::SHT_NOBITS) { From b64505af4db61e75ef3277d43fbe61286ce33847 Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Tue, 1 Jul 2025 18:06:27 -0700 Subject: [PATCH 16/16] [Frontend] Destroy compiling compiler instance before read https://github.com/llvm/llvm-project/pull/134887 added a clone for the compiler instance in `compileModuleAndReadASTImpl`, which would then be destroyed *after* the corresponding read in the importing instance. Swift has a `SwiftNameLookupExtension` module extension which updates (effectively) global state - populating the lookup table for a module on read and removing it when the module is destroyed. With newly cloned instance, we would then see: - Module compiled with cloned instance - Module read with importing instance - Lookup table for that module added - Cloned instance destroyed - Module from that cloned instance destroyed - Lookup table for that module name removed Depending on the original semantics is incredibly fragile, but for now it's good enough to ensure that the read in the importing instance is after the cloned instanced is destroyed. Ideally we'd only ever add to the lookup tables in the original importing instance, never its clones. --- clang/lib/Frontend/CompilerInstance.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 6499e47d0da4d..6855e6baa22ce 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1655,16 +1655,18 @@ static bool compileModuleAndReadASTImpl(CompilerInstance &ImportingInstance, SourceLocation ModuleNameLoc, Module *Module, StringRef ModuleFileName) { - auto Instance = ImportingInstance.cloneForModuleCompile(ModuleNameLoc, Module, - ModuleFileName); - - if (!ImportingInstance.compileModule(ModuleNameLoc, - Module->getTopLevelModuleName(), - ModuleFileName, *Instance)) { - ImportingInstance.getDiagnostics().Report(ModuleNameLoc, - diag::err_module_not_built) - << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); - return false; + { + auto Instance = ImportingInstance.cloneForModuleCompile(ModuleNameLoc, Module, + ModuleFileName); + + if (!ImportingInstance.compileModule(ModuleNameLoc, + Module->getTopLevelModuleName(), + ModuleFileName, *Instance)) { + ImportingInstance.getDiagnostics().Report(ModuleNameLoc, + diag::err_module_not_built) + << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); + return false; + } } return readASTAfterCompileModule(ImportingInstance, ImportLoc, ModuleNameLoc,