summaryrefslogtreecommitdiff
path: root/gnu/llvm/clang/tools
diff options
context:
space:
mode:
authorRobert Nagy <robert@cvs.openbsd.org>2023-11-11 18:17:06 +0000
committerRobert Nagy <robert@cvs.openbsd.org>2023-11-11 18:17:06 +0000
commita388acc7d111eece16e7c46f357872ec47588443 (patch)
treea636add3cb3f4afb8c45bb8302545f79f9e37d37 /gnu/llvm/clang/tools
parent77976eff798a4c323c3194ff91190574c44d047d (diff)
import of clang from LLVM-16.0.6
Diffstat (limited to 'gnu/llvm/clang/tools')
-rw-r--r--gnu/llvm/clang/tools/CMakeLists.txt8
-rw-r--r--gnu/llvm/clang/tools/amdgpu-arch/AMDGPUArch.cpp89
-rw-r--r--gnu/llvm/clang/tools/amdgpu-arch/CMakeLists.txt17
-rw-r--r--gnu/llvm/clang/tools/c-index-test/CMakeLists.txt9
-rw-r--r--gnu/llvm/clang/tools/c-index-test/c-index-test.c109
-rw-r--r--gnu/llvm/clang/tools/c-index-test/core_main.cpp6
-rw-r--r--gnu/llvm/clang/tools/clang-check/ClangCheck.cpp51
-rw-r--r--gnu/llvm/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp106
-rw-r--r--gnu/llvm/clang/tools/clang-format/.clang-format4
-rw-r--r--gnu/llvm/clang/tools/clang-format/CMakeLists.txt20
-rw-r--r--gnu/llvm/clang/tools/clang-format/ClangFormat.cpp128
-rwxr-xr-xgnu/llvm/clang/tools/clang-format/clang-format-diff.py19
-rw-r--r--gnu/llvm/clang/tools/clang-format/clang-format.el2
-rw-r--r--gnu/llvm/clang/tools/clang-format/clang-format.py10
-rwxr-xr-xgnu/llvm/clang/tools/clang-format/git-clang-format161
-rw-r--r--gnu/llvm/clang/tools/clang-fuzzer/CMakeLists.txt3
-rw-r--r--gnu/llvm/clang/tools/clang-fuzzer/dictionary/CMakeLists.txt4
-rw-r--r--gnu/llvm/clang/tools/clang-fuzzer/dictionary/dictionary.c57
-rw-r--r--gnu/llvm/clang/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp2
-rw-r--r--gnu/llvm/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt2
-rw-r--r--gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt3
-rw-r--r--gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp106
-rw-r--r--gnu/llvm/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt2
-rw-r--r--gnu/llvm/clang/tools/clang-import-test/CMakeLists.txt1
-rw-r--r--gnu/llvm/clang/tools/clang-import-test/clang-import-test.cpp21
-rw-r--r--gnu/llvm/clang/tools/clang-linker-wrapper/CMakeLists.txt45
-rw-r--r--gnu/llvm/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp1442
-rw-r--r--gnu/llvm/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td124
-rw-r--r--gnu/llvm/clang/tools/clang-linker-wrapper/OffloadWrapper.cpp622
-rw-r--r--gnu/llvm/clang/tools/clang-linker-wrapper/OffloadWrapper.h28
-rw-r--r--gnu/llvm/clang/tools/clang-offload-bundler/CMakeLists.txt11
-rw-r--r--gnu/llvm/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp1412
-rw-r--r--gnu/llvm/clang/tools/clang-offload-packager/CMakeLists.txt19
-rw-r--r--gnu/llvm/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp221
-rw-r--r--gnu/llvm/clang/tools/clang-refactor/ClangRefactor.cpp18
-rw-r--r--gnu/llvm/clang/tools/clang-refactor/TestSupport.cpp15
-rw-r--r--gnu/llvm/clang/tools/clang-refactor/TestSupport.h7
-rw-r--r--gnu/llvm/clang/tools/clang-rename/CMakeLists.txt8
-rw-r--r--gnu/llvm/clang/tools/clang-rename/ClangRename.cpp6
-rw-r--r--gnu/llvm/clang/tools/clang-repl/CMakeLists.txt8
-rw-r--r--gnu/llvm/clang/tools/clang-repl/ClangRepl.cpp50
-rw-r--r--gnu/llvm/clang/tools/clang-scan-deps/CMakeLists.txt2
-rw-r--r--gnu/llvm/clang/tools/clang-scan-deps/ClangScanDeps.cpp550
-rwxr-xr-xgnu/llvm/clang/tools/diag-build/diag-build.sh2
-rw-r--r--gnu/llvm/clang/tools/diagtool/DiagTool.cpp1
-rw-r--r--gnu/llvm/clang/tools/diagtool/DiagnosticNames.cpp15
-rw-r--r--gnu/llvm/clang/tools/diagtool/FindDiagnosticID.cpp9
-rw-r--r--gnu/llvm/clang/tools/diagtool/ShowEnabledWarnings.cpp7
-rw-r--r--gnu/llvm/clang/tools/diagtool/TreeView.cpp6
-rw-r--r--gnu/llvm/clang/tools/driver/CMakeLists.txt14
-rw-r--r--gnu/llvm/clang/tools/driver/cc1_main.cpp25
-rw-r--r--gnu/llvm/clang/tools/driver/cc1as_main.cpp65
-rw-r--r--gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp7
-rw-r--r--gnu/llvm/clang/tools/driver/driver.cpp221
-rw-r--r--gnu/llvm/clang/tools/include-mapping/cppreference_parser.py188
-rwxr-xr-xgnu/llvm/clang/tools/include-mapping/gen_std.py126
-rwxr-xr-xgnu/llvm/clang/tools/include-mapping/test.py155
-rw-r--r--gnu/llvm/clang/tools/libclang/BuildSystem.cpp1
-rw-r--r--gnu/llvm/clang/tools/libclang/CIndex.cpp446
-rw-r--r--gnu/llvm/clang/tools/libclang/CIndexCodeCompletion.cpp14
-rw-r--r--gnu/llvm/clang/tools/libclang/CIndexHigh.cpp4
-rw-r--r--gnu/llvm/clang/tools/libclang/CIndexInclusionStack.cpp4
-rw-r--r--gnu/llvm/clang/tools/libclang/CIndexer.cpp22
-rw-r--r--gnu/llvm/clang/tools/libclang/CMakeLists.txt24
-rw-r--r--gnu/llvm/clang/tools/libclang/CXCursor.cpp133
-rw-r--r--gnu/llvm/clang/tools/libclang/CXExtractAPI.cpp151
-rw-r--r--gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.cpp27
-rw-r--r--gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.h15
-rw-r--r--gnu/llvm/clang/tools/libclang/CXLoadedDiagnostic.cpp2
-rw-r--r--gnu/llvm/clang/tools/libclang/CXString.cpp11
-rw-r--r--gnu/llvm/clang/tools/libclang/CXType.cpp44
-rw-r--r--gnu/llvm/clang/tools/libclang/CXType.h3
-rw-r--r--gnu/llvm/clang/tools/libclang/CursorVisitor.h14
-rw-r--r--gnu/llvm/clang/tools/libclang/FatalErrorHandler.cpp5
-rw-r--r--gnu/llvm/clang/tools/libclang/Indexing.cpp16
-rw-r--r--gnu/llvm/clang/tools/libclang/libclang.map13
-rw-r--r--gnu/llvm/clang/tools/nvptx-arch/CMakeLists.txt26
-rw-r--r--gnu/llvm/clang/tools/nvptx-arch/NVPTXArch.cpp116
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/CMakeLists.txt18
-rwxr-xr-xgnu/llvm/clang/tools/scan-build-py/bin/analyze-build2
-rwxr-xr-xgnu/llvm/clang/tools/scan-build-py/bin/intercept-build2
-rwxr-xr-xgnu/llvm/clang/tools/scan-build-py/bin/scan-build2
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/lib/libear/ear.c8
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/analyze.py12
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/report.py2
-rwxr-xr-xgnu/llvm/clang/tools/scan-build-py/libexec/analyze-c++2
-rwxr-xr-xgnu/llvm/clang/tools/scan-build-py/libexec/analyze-cc2
-rwxr-xr-xgnu/llvm/clang/tools/scan-build-py/libexec/intercept-c++2
-rwxr-xr-xgnu/llvm/clang/tools/scan-build-py/libexec/intercept-cc2
-rw-r--r--gnu/llvm/clang/tools/scan-build/CMakeLists.txt20
-rwxr-xr-xgnu/llvm/clang/tools/scan-build/bin/scan-build48
-rwxr-xr-xgnu/llvm/clang/tools/scan-build/libexec/ccc-analyzer11
-rw-r--r--gnu/llvm/clang/tools/scan-build/man/scan-build.16
-rw-r--r--gnu/llvm/clang/tools/scan-view/CMakeLists.txt4
94 files changed, 5575 insertions, 2028 deletions
diff --git a/gnu/llvm/clang/tools/CMakeLists.txt b/gnu/llvm/clang/tools/CMakeLists.txt
index c929f6e665e..f60db6ef0ba 100644
--- a/gnu/llvm/clang/tools/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/CMakeLists.txt
@@ -8,10 +8,13 @@ add_clang_subdirectory(clang-format)
add_clang_subdirectory(clang-format-vs)
add_clang_subdirectory(clang-fuzzer)
add_clang_subdirectory(clang-import-test)
+add_clang_subdirectory(clang-linker-wrapper)
+add_clang_subdirectory(clang-offload-packager)
add_clang_subdirectory(clang-offload-bundler)
-add_clang_subdirectory(clang-offload-wrapper)
add_clang_subdirectory(clang-scan-deps)
-add_clang_subdirectory(clang-repl)
+if(HAVE_CLANG_REPL_SUPPORT)
+ add_clang_subdirectory(clang-repl)
+endif()
add_clang_subdirectory(c-index-test)
@@ -47,3 +50,4 @@ add_llvm_external_project(clang-tools-extra extra)
add_clang_subdirectory(libclang)
add_clang_subdirectory(amdgpu-arch)
+add_clang_subdirectory(nvptx-arch)
diff --git a/gnu/llvm/clang/tools/amdgpu-arch/AMDGPUArch.cpp b/gnu/llvm/clang/tools/amdgpu-arch/AMDGPUArch.cpp
index 4fae78b4f12..2fdd398c9c6 100644
--- a/gnu/llvm/clang/tools/amdgpu-arch/AMDGPUArch.cpp
+++ b/gnu/llvm/clang/tools/amdgpu-arch/AMDGPUArch.cpp
@@ -11,26 +11,75 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+#if DYNAMIC_HSA
+typedef enum {
+ HSA_STATUS_SUCCESS = 0x0,
+} hsa_status_t;
+
+typedef enum {
+ HSA_DEVICE_TYPE_CPU = 0,
+ HSA_DEVICE_TYPE_GPU = 1,
+} hsa_device_type_t;
+
+typedef enum {
+ HSA_AGENT_INFO_NAME = 0,
+ HSA_AGENT_INFO_DEVICE = 17,
+} hsa_agent_info_t;
+
+typedef struct hsa_agent_s {
+ uint64_t handle;
+} hsa_agent_t;
+
+hsa_status_t (*hsa_init)();
+hsa_status_t (*hsa_shut_down)();
+hsa_status_t (*hsa_agent_get_info)(hsa_agent_t, hsa_agent_info_t, void *);
+hsa_status_t (*hsa_iterate_agents)(hsa_status_t (*)(hsa_agent_t, void *),
+ void *);
+
+constexpr const char *DynamicHSAPath = "libhsa-runtime64.so";
+
+llvm::Error loadHSA() {
+ std::string ErrMsg;
+ auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
+ llvm::sys::DynamicLibrary::getPermanentLibrary(DynamicHSAPath, &ErrMsg));
+ if (!DynlibHandle->isValid()) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Failed to 'dlopen' %s", DynamicHSAPath);
+ }
+#define DYNAMIC_INIT(SYMBOL) \
+ { \
+ void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL); \
+ if (!SymbolPtr) \
+ return llvm::createStringError(llvm::inconvertibleErrorCode(), \
+ "Failed to 'dlsym' " #SYMBOL); \
+ SYMBOL = reinterpret_cast<decltype(SYMBOL)>(SymbolPtr); \
+ }
+ DYNAMIC_INIT(hsa_init);
+ DYNAMIC_INIT(hsa_shut_down);
+ DYNAMIC_INIT(hsa_agent_get_info);
+ DYNAMIC_INIT(hsa_iterate_agents);
+#undef DYNAMIC_INIT
+ return llvm::Error::success();
+}
+#else
+
#if defined(__has_include)
-#if __has_include("hsa.h")
-#define HSA_HEADER_FOUND 1
-#include "hsa.h"
-#elif __has_include("hsa/hsa.h")
-#define HSA_HEADER_FOUND 1
+#if __has_include("hsa/hsa.h")
#include "hsa/hsa.h"
-#else
-#define HSA_HEADER_FOUND 0
+#elif __has_include("hsa.h")
+#include "hsa.h"
#endif
-#else
-#define HSA_HEADER_FOUND 0
+#include "hsa/hsa.h"
#endif
-#if !HSA_HEADER_FOUND
-int main() { return 1; }
-#else
-
-#include <string>
-#include <vector>
+llvm::Error loadHSA() { return llvm::Error::success(); }
+#endif
static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) {
hsa_device_type_t DeviceType;
@@ -53,7 +102,13 @@ static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) {
return HSA_STATUS_SUCCESS;
}
-int main() {
+int main(int argc, char *argv[]) {
+ // Attempt to load the HSA runtime.
+ if (llvm::Error Err = loadHSA()) {
+ logAllUnhandledErrors(std::move(Err), llvm::errs());
+ return 1;
+ }
+
hsa_status_t Status = hsa_init();
if (Status != HSA_STATUS_SUCCESS) {
return 1;
@@ -74,5 +129,3 @@ int main() {
hsa_shut_down();
return 0;
}
-
-#endif
diff --git a/gnu/llvm/clang/tools/amdgpu-arch/CMakeLists.txt b/gnu/llvm/clang/tools/amdgpu-arch/CMakeLists.txt
index caead440c5c..2028cc266b5 100644
--- a/gnu/llvm/clang/tools/amdgpu-arch/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/amdgpu-arch/CMakeLists.txt
@@ -6,14 +6,15 @@
# //
# //===----------------------------------------------------------------------===//
-find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
-if (NOT ${hsa-runtime64_FOUND})
- message(STATUS "Not building amdgpu-arch: hsa-runtime64 not found")
- return()
-endif()
+set(LLVM_LINK_COMPONENTS Support)
add_clang_tool(amdgpu-arch AMDGPUArch.cpp)
-set_target_properties(amdgpu-arch PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON)
-
-clang_target_link_libraries(amdgpu-arch PRIVATE hsa-runtime64::hsa-runtime64)
+# If we find the HSA runtime we link with it directly.
+find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
+if (${hsa-runtime64_FOUND})
+ set_target_properties(amdgpu-arch PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON)
+ target_link_libraries(amdgpu-arch PRIVATE hsa-runtime64::hsa-runtime64)
+else()
+ target_compile_definitions(amdgpu-arch PRIVATE "DYNAMIC_HSA")
+endif()
diff --git a/gnu/llvm/clang/tools/c-index-test/CMakeLists.txt b/gnu/llvm/clang/tools/c-index-test/CMakeLists.txt
index ceef4b08637..0ae1b4e5524 100644
--- a/gnu/llvm/clang/tools/c-index-test/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/c-index-test/CMakeLists.txt
@@ -40,12 +40,7 @@ set_target_properties(c-index-test
# If libxml2 is available, make it available for c-index-test.
if (CLANG_HAVE_LIBXML)
- if ((CMAKE_OSX_SYSROOT) AND (EXISTS ${CMAKE_OSX_SYSROOT}/${LIBXML2_INCLUDE_DIR}))
- include_directories(SYSTEM ${CMAKE_OSX_SYSROOT}/${LIBXML2_INCLUDE_DIR})
- else()
- include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
- endif()
- target_link_libraries(c-index-test PRIVATE ${LIBXML2_LIBRARIES})
+ target_link_libraries(c-index-test PRIVATE LibXml2::LibXml2)
endif()
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
@@ -54,7 +49,7 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
set_property(TARGET c-index-test APPEND PROPERTY INSTALL_RPATH
"@executable_path/../../lib")
else()
- set(INSTALL_DESTINATION bin)
+ set(INSTALL_DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif()
install(TARGETS c-index-test
diff --git a/gnu/llvm/clang/tools/c-index-test/c-index-test.c b/gnu/llvm/clang/tools/c-index-test/c-index-test.c
index a32062caf88..cc425fc51ef 100644
--- a/gnu/llvm/clang/tools/c-index-test/c-index-test.c
+++ b/gnu/llvm/clang/tools/c-index-test/c-index-test.c
@@ -1,15 +1,17 @@
/* c-index-test.c */
-#include "clang/Config/config.h"
-#include "clang-c/Index.h"
-#include "clang-c/CXCompilationDatabase.h"
#include "clang-c/BuildSystem.h"
+#include "clang-c/CXCompilationDatabase.h"
+#include "clang-c/CXErrorCode.h"
+#include "clang-c/CXString.h"
#include "clang-c/Documentation.h"
+#include "clang-c/Index.h"
+#include "clang/Config/config.h"
+#include <assert.h>
#include <ctype.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <assert.h>
#ifdef CLANG_HAVE_LIBXML
#include <libxml/parser.h>
@@ -66,7 +68,7 @@ extern char *dirname(char *);
#endif
/** Return the default parsing options. */
-static unsigned getDefaultParsingOptions() {
+static unsigned getDefaultParsingOptions(void) {
unsigned options = CXTranslationUnit_DetailedPreprocessingRecord;
if (getenv("CINDEXTEST_EDITING"))
@@ -900,6 +902,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
printf(" (mutable)");
if (clang_CXXMethod_isDefaulted(Cursor))
printf(" (defaulted)");
+ if (clang_CXXMethod_isDeleted(Cursor))
+ printf(" (deleted)");
if (clang_CXXMethod_isStatic(Cursor))
printf(" (static)");
if (clang_CXXMethod_isVirtual(Cursor))
@@ -908,6 +912,10 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
printf(" (const)");
if (clang_CXXMethod_isPureVirtual(Cursor))
printf(" (pure)");
+ if (clang_CXXMethod_isCopyAssignmentOperator(Cursor))
+ printf(" (copy-assignment operator)");
+ if (clang_CXXMethod_isMoveAssignmentOperator(Cursor))
+ printf(" (move-assignment operator)");
if (clang_CXXRecord_isAbstract(Cursor))
printf(" (abstract)");
if (clang_EnumDecl_isScoped(Cursor))
@@ -1000,7 +1008,10 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
clang_getCString(Name), line, column);
clang_disposeString(Name);
- if (Cursor.kind == CXCursor_FunctionDecl) {
+ if (Cursor.kind == CXCursor_FunctionDecl
+ || Cursor.kind == CXCursor_StructDecl
+ || Cursor.kind == CXCursor_ClassDecl
+ || Cursor.kind == CXCursor_ClassTemplatePartialSpecialization) {
/* Collect the template parameter kinds from the base template. */
int NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
int I;
@@ -1831,6 +1842,18 @@ static enum CXChildVisitResult PrintManglings(CXCursor cursor, CXCursor p,
return CXChildVisit_Recurse;
}
+static enum CXChildVisitResult
+PrintSingleSymbolSGFs(CXCursor cursor, CXCursor parent, CXClientData data) {
+ CXString SGFData = clang_getSymbolGraphForCursor(cursor);
+ const char *SGF = clang_getCString(SGFData);
+ if (SGF)
+ printf("%s\n", SGF);
+
+ clang_disposeString(SGFData);
+
+ return CXChildVisit_Recurse;
+}
+
/******************************************************************************/
/* Bitwidth testing. */
/******************************************************************************/
@@ -3316,7 +3339,7 @@ typedef struct {
unsigned num_files;
} ImportedASTFilesData;
-static ImportedASTFilesData *importedASTs_create() {
+static ImportedASTFilesData *importedASTs_create(void) {
ImportedASTFilesData *p;
p = malloc(sizeof(ImportedASTFilesData));
assert(p);
@@ -3504,6 +3527,8 @@ static const char *getEntityKindString(CXIdxEntityKind kind) {
case CXIdxEntity_CXXConversionFunction: return "conversion-func";
case CXIdxEntity_CXXTypeAlias: return "type-alias";
case CXIdxEntity_CXXInterface: return "c++-__interface";
+ case CXIdxEntity_CXXConcept:
+ return "concept";
}
assert(0 && "Garbage entity kind");
return 0;
@@ -4407,7 +4432,7 @@ static void print_usr(CXString usr) {
clang_disposeString(usr);
}
-static void display_usrs() {
+static void display_usrs(void) {
fprintf(stderr, "-print-usrs options:\n"
" ObjCCategory <class name> <category name>\n"
" ObjCClass <class name>\n"
@@ -4780,6 +4805,64 @@ static int perform_print_build_session_timestamp(void) {
return 0;
}
+static int perform_test_single_symbol_sgf(const char *input, int argc,
+ const char *argv[]) {
+ CXIndex Idx;
+ CXTranslationUnit TU;
+ CXAPISet API;
+ struct CXUnsavedFile *unsaved_files = 0;
+ int num_unsaved_files = 0;
+ enum CXErrorCode Err;
+ int result = 0;
+ const char *InvocationPath;
+ CXString SGF;
+ const char *usr;
+
+ usr = input + strlen("-single-symbol-sgf-for=");
+
+ Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
+ /* displayDiagnostics=*/0);
+ InvocationPath = getenv("CINDEXTEST_INVOCATION_EMISSION_PATH");
+ if (InvocationPath)
+ clang_CXIndex_setInvocationEmissionPathOption(Idx, InvocationPath);
+
+ if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
+ result = -1;
+ goto dispose_index;
+ }
+
+ Err = clang_parseTranslationUnit2(
+ Idx, 0, argv + num_unsaved_files, argc - num_unsaved_files, unsaved_files,
+ num_unsaved_files, getDefaultParsingOptions(), &TU);
+ if (Err != CXError_Success) {
+ fprintf(stderr, "Unable to load translation unit!\n");
+ describeLibclangFailure(Err);
+ result = 1;
+ goto free_remapped_files;
+ }
+
+ Err = clang_createAPISet(TU, &API);
+ if (Err != CXError_Success) {
+ fprintf(stderr,
+ "Unable to create API Set for API information extraction!\n");
+ result = 2;
+ goto dispose_tu;
+ }
+
+ SGF = clang_getSymbolGraphForUSR(usr, API);
+ printf("%s", clang_getCString(SGF));
+
+ clang_disposeString(SGF);
+ clang_disposeAPISet(API);
+dispose_tu:
+ clang_disposeTranslationUnit(TU);
+free_remapped_files:
+ free_remapped_files(unsaved_files, num_unsaved_files);
+dispose_index:
+ clang_disposeIndex(Idx);
+ return result;
+}
+
/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
@@ -4838,6 +4921,9 @@ static void print_usage(void) {
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n");
fprintf(stderr,
+ " c-index-test -single-symbol-sgfs <symbol filter> {<args>*}\n"
+ " c-index-test -single-symbol-sgf-for=<usr> {<args>}*\n");
+ fprintf(stderr,
" c-index-test -write-pch <file> <compiler arguments>\n"
" c-index-test -compilation-db [lookup <filename>] database\n");
fprintf(stderr,
@@ -4969,6 +5055,11 @@ int cindextest_main(int argc, const char **argv) {
return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2);
else if (argc == 2 && strcmp(argv[1], "-print-build-session-timestamp") == 0)
return perform_print_build_session_timestamp();
+ else if (argc > 3 && strcmp(argv[1], "-single-symbol-sgfs") == 0)
+ return perform_test_load_source(argc - 3, argv + 3, argv[2],
+ PrintSingleSymbolSGFs, NULL);
+ else if (argc > 2 && strstr(argv[1], "-single-symbol-sgf-for=") == argv[1])
+ return perform_test_single_symbol_sgf(argv[1], argc - 2, argv + 2);
print_usage();
return 1;
diff --git a/gnu/llvm/clang/tools/c-index-test/core_main.cpp b/gnu/llvm/clang/tools/c-index-test/core_main.cpp
index 7037252ffa0..ea15b2bcd5c 100644
--- a/gnu/llvm/clang/tools/c-index-test/core_main.cpp
+++ b/gnu/llvm/clang/tools/c-index-test/core_main.cpp
@@ -13,6 +13,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Index/IndexDataConsumer.h"
#include "clang/Index/IndexingAction.h"
#include "clang/Index/USRGeneration.h"
@@ -220,7 +221,10 @@ static bool printSourceSymbols(const char *Executable,
ArgsWithProgName.append(Args.begin(), Args.end());
IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
- auto CInvok = createInvocationFromCommandLine(ArgsWithProgName, Diags);
+ CreateInvocationOptions CIOpts;
+ CIOpts.Diags = Diags;
+ CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
+ auto CInvok = createInvocation(ArgsWithProgName, std::move(CIOpts));
if (!CInvok)
return true;
diff --git a/gnu/llvm/clang/tools/clang-check/ClangCheck.cpp b/gnu/llvm/clang/tools/clang-check/ClangCheck.cpp
index 11fdeb71fd9..0524becf4f4 100644
--- a/gnu/llvm/clang/tools/clang-check/ClangCheck.cpp
+++ b/gnu/llvm/clang/tools/clang-check/ClangCheck.cpp
@@ -25,6 +25,7 @@
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/Tooling/Syntax/TokenBufferTokenManager.h"
#include "clang/Tooling/Syntax/Tokens.h"
#include "clang/Tooling/Syntax/Tree.h"
#include "clang/Tooling/Tooling.h"
@@ -76,6 +77,10 @@ static cl::opt<bool>
Analyze("analyze",
cl::desc(Options.getOptionHelpText(options::OPT_analyze)),
cl::cat(ClangCheckCategory));
+static cl::opt<std::string>
+ AnalyzerOutput("analyzer-output-path",
+ cl::desc(Options.getOptionHelpText(options::OPT_o)),
+ cl::cat(ClangCheckCategory));
static cl::opt<bool>
Fixit("fixit", cl::desc(Options.getOptionHelpText(options::OPT_fixit)),
@@ -153,9 +158,11 @@ public:
clang::syntax::TokenBuffer TB = std::move(Collector).consume();
if (TokensDump)
llvm::outs() << TB.dumpForTests();
- clang::syntax::Arena A(AST.getSourceManager(), AST.getLangOpts(), TB);
- llvm::outs() << clang::syntax::buildSyntaxTree(A, AST)->dump(
- AST.getSourceManager());
+ clang::syntax::TokenBufferTokenManager TBTM(TB, AST.getLangOpts(),
+ AST.getSourceManager());
+ clang::syntax::Arena A;
+ llvm::outs()
+ << clang::syntax::buildSyntaxTree(A, TBTM, AST)->dump(TBTM);
}
private:
@@ -204,15 +211,37 @@ int main(int argc, const char **argv) {
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
- // Clear adjusters because -fsyntax-only is inserted by the default chain.
- Tool.clearArgumentsAdjusters();
- Tool.appendArgumentsAdjuster(getClangStripOutputAdjuster());
- Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
+ if (Analyze) {
+ // Set output path if is provided by user.
+ //
+ // As the original -o options have been removed by default via the
+ // strip-output adjuster, we only need to add the analyzer -o options here
+ // when it is provided by users.
+ if (!AnalyzerOutput.empty())
+ Tool.appendArgumentsAdjuster(
+ getInsertArgumentAdjuster(CommandLineArguments{"-o", AnalyzerOutput},
+ ArgumentInsertPosition::END));
- // Running the analyzer requires --analyze. Other modes can work with the
- // -fsyntax-only option.
- Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster(
- Analyze ? "--analyze" : "-fsyntax-only", ArgumentInsertPosition::BEGIN));
+ // Running the analyzer requires --analyze. Other modes can work with the
+ // -fsyntax-only option.
+ //
+ // The syntax-only adjuster is installed by default.
+ // Good: It also strips options that trigger extra output, like -save-temps.
+ // Bad: We don't want the -fsyntax-only when executing the static analyzer.
+ //
+ // To enable the static analyzer, we first strip all -fsyntax-only options
+ // and then add an --analyze option to the front.
+ Tool.appendArgumentsAdjuster(
+ [&](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments AdjustedArgs;
+ for (const std::string &Arg : Args)
+ if (Arg != "-fsyntax-only")
+ AdjustedArgs.emplace_back(Arg);
+ return AdjustedArgs;
+ });
+ Tool.appendArgumentsAdjuster(
+ getInsertArgumentAdjuster("--analyze", ArgumentInsertPosition::BEGIN));
+ }
ClangCheckActionFactory CheckFactory;
std::unique_ptr<FrontendActionFactory> FrontendFactory;
diff --git a/gnu/llvm/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/gnu/llvm/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
index 8aba1301ef9..2a1e605ec4f 100644
--- a/gnu/llvm/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
+++ b/gnu/llvm/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
@@ -1,4 +1,4 @@
-//===- ClangExtDefMapGen.cpp -----------------------------------------------===//
+//===- ClangExtDefMapGen.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -13,14 +13,17 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
+#include <optional>
#include <sstream>
#include <string>
@@ -29,12 +32,16 @@ using namespace clang;
using namespace clang::cross_tu;
using namespace clang::tooling;
-static cl::OptionCategory ClangExtDefMapGenCategory("clang-extdefmapgen options");
+static cl::OptionCategory
+ ClangExtDefMapGenCategory("clang-extdefmapgen options");
class MapExtDefNamesConsumer : public ASTConsumer {
public:
- MapExtDefNamesConsumer(ASTContext &Context)
- : Ctx(Context), SM(Context.getSourceManager()) {}
+ MapExtDefNamesConsumer(ASTContext &Context,
+ StringRef astFilePath = StringRef())
+ : Ctx(Context), SM(Context.getSourceManager()) {
+ CurrentFileName = astFilePath.str();
+ }
~MapExtDefNamesConsumer() {
// Flush results to standard output.
@@ -64,7 +71,7 @@ void MapExtDefNamesConsumer::handleDecl(const Decl *D) {
if (const Stmt *Body = FD->getBody())
addIfInMain(FD, Body->getBeginLoc());
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
- if (cross_tu::containsConst(VD, Ctx) && VD->hasInit())
+ if (cross_tu::shouldImport(VD, Ctx) && VD->hasInit())
if (const Expr *Init = VD->getInit())
addIfInMain(VD, Init->getBeginLoc());
}
@@ -76,7 +83,7 @@ void MapExtDefNamesConsumer::handleDecl(const Decl *D) {
void MapExtDefNamesConsumer::addIfInMain(const DeclaratorDecl *DD,
SourceLocation defStart) {
- llvm::Optional<std::string> LookupName =
+ std::optional<std::string> LookupName =
CrossTranslationUnitContext::getLookupName(DD);
if (!LookupName)
return;
@@ -111,6 +118,82 @@ protected:
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+
+IntrusiveRefCntPtr<DiagnosticsEngine> GetDiagnosticsEngine() {
+ if (Diags) {
+ // Call reset to make sure we don't mix errors
+ Diags->Reset(false);
+ return Diags;
+ }
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter *DiagClient =
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ DiagClient->setPrefix("clang-extdef-mappping");
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+
+ IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
+ new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
+ Diags.swap(DiagEngine);
+
+ // Retain this one time so it's not destroyed by ASTUnit::LoadFromASTFile
+ Diags->Retain();
+ return Diags;
+}
+
+static CompilerInstance *CI = nullptr;
+
+static bool HandleAST(StringRef AstPath) {
+
+ if (!CI)
+ CI = new CompilerInstance();
+
+ IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine = GetDiagnosticsEngine();
+
+ std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
+ AstPath.str(), CI->getPCHContainerOperations()->getRawReader(),
+ ASTUnit::LoadASTOnly, DiagEngine, CI->getFileSystemOpts());
+
+ if (!Unit)
+ return false;
+
+ FileManager FM(CI->getFileSystemOpts());
+ SmallString<128> AbsPath(AstPath);
+ FM.makeAbsolutePath(AbsPath);
+
+ MapExtDefNamesConsumer Consumer =
+ MapExtDefNamesConsumer(Unit->getASTContext(), AbsPath);
+ Consumer.HandleTranslationUnit(Unit->getASTContext());
+
+ return true;
+}
+
+static int HandleFiles(ArrayRef<std::string> SourceFiles,
+ CompilationDatabase &compilations) {
+ std::vector<std::string> SourcesToBeParsed;
+
+ // Loop over all input files, if they are pre-compiled AST
+ // process them directly in HandleAST, otherwise put them
+ // on a list for ClangTool to handle.
+ for (StringRef Src : SourceFiles) {
+ if (Src.endswith(".ast")) {
+ if (!HandleAST(Src)) {
+ return 1;
+ }
+ } else {
+ SourcesToBeParsed.push_back(Src.str());
+ }
+ }
+
+ if (!SourcesToBeParsed.empty()) {
+ ClangTool Tool(compilations, SourcesToBeParsed);
+ return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get());
+ }
+
+ return 0;
+}
+
int main(int argc, const char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal(argv[0], false);
@@ -118,7 +201,10 @@ int main(int argc, const char **argv) {
const char *Overview = "\nThis tool collects the USR name and location "
"of external definitions in the source files "
- "(excluding headers).\n";
+ "(excluding headers).\n"
+ "Input can be either source files that are compiled "
+ "with compile database or .ast files that are "
+ "created from clang's -emit-ast option.\n";
auto ExpectedParser = CommonOptionsParser::create(
argc, argv, ClangExtDefMapGenCategory, cl::ZeroOrMore, Overview);
if (!ExpectedParser) {
@@ -127,8 +213,6 @@ int main(int argc, const char **argv) {
}
CommonOptionsParser &OptionsParser = ExpectedParser.get();
- ClangTool Tool(OptionsParser.getCompilations(),
- OptionsParser.getSourcePathList());
-
- return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get());
+ return HandleFiles(OptionsParser.getSourcePathList(),
+ OptionsParser.getCompilations());
}
diff --git a/gnu/llvm/clang/tools/clang-format/.clang-format b/gnu/llvm/clang/tools/clang-format/.clang-format
new file mode 100644
index 00000000000..60f4950c01a
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-format/.clang-format
@@ -0,0 +1,4 @@
+BasedOnStyle: LLVM
+InsertBraces: true
+LineEnding: LF
+RemoveBracesLLVM: true
diff --git a/gnu/llvm/clang/tools/clang-format/CMakeLists.txt b/gnu/llvm/clang/tools/clang-format/CMakeLists.txt
index 35ecdb11253..30c93f8667c 100644
--- a/gnu/llvm/clang/tools/clang-format/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-format/CMakeLists.txt
@@ -20,21 +20,21 @@ if( LLVM_LIB_FUZZING_ENGINE OR LLVM_USE_SANITIZE_COVERAGE )
add_subdirectory(fuzzer)
endif()
-install(PROGRAMS clang-format-bbedit.applescript
- DESTINATION share/clang
+install(FILES clang-format-bbedit.applescript
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-format)
install(PROGRAMS clang-format-diff.py
- DESTINATION share/clang
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-format)
-install(PROGRAMS clang-format-sublime.py
- DESTINATION share/clang
+install(FILES clang-format-sublime.py
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-format)
-install(PROGRAMS clang-format.el
- DESTINATION share/clang
+install(FILES clang-format.el
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-format)
-install(PROGRAMS clang-format.py
- DESTINATION share/clang
+install(FILES clang-format.py
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-format)
install(PROGRAMS git-clang-format
- DESTINATION bin
+ DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT clang-format)
diff --git a/gnu/llvm/clang/tools/clang-format/ClangFormat.cpp b/gnu/llvm/clang/tools/clang-format/ClangFormat.cpp
index 144e87f78c6..dab8a7f2f8c 100644
--- a/gnu/llvm/clang/tools/clang-format/ClangFormat.cpp
+++ b/gnu/llvm/clang/tools/clang-format/ClangFormat.cpp
@@ -19,10 +19,12 @@
#include "clang/Basic/Version.h"
#include "clang/Format/Format.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Process.h"
+#include <fstream>
using namespace llvm;
using clang::tooling::Replacements;
@@ -68,16 +70,29 @@ static cl::opt<std::string>
cl::desc("The name of the predefined style used as a\n"
"fallback in case clang-format is invoked with\n"
"-style=file, but can not find the .clang-format\n"
- "file to use.\n"
+ "file to use. Defaults to 'LLVM'.\n"
"Use -fallback-style=none to skip formatting."),
cl::init(clang::format::DefaultFallbackStyle),
cl::cat(ClangFormatCategory));
static cl::opt<std::string> AssumeFileName(
"assume-filename",
- cl::desc("Override filename used to determine the language.\n"
- "When reading from stdin, clang-format assumes this\n"
- "filename to determine the language."),
+ cl::desc("Set filename used to determine the language and to find\n"
+ ".clang-format file.\n"
+ "Only used when reading from stdin.\n"
+ "If this is not passed, the .clang-format file is searched\n"
+ "relative to the current working directory when reading stdin.\n"
+ "Unrecognized filenames are treated as C++.\n"
+ "supported:\n"
+ " CSharp: .cs\n"
+ " Java: .java\n"
+ " JavaScript: .mjs .js .ts\n"
+ " Json: .json\n"
+ " Objective-C: .m .mm\n"
+ " Proto: .proto .protodevel\n"
+ " TableGen: .td\n"
+ " TextProto: .textpb .pb.txt .textproto .asciipb\n"
+ " Verilog: .sv .svh .v .vh"),
cl::init("<stdin>"), cl::cat(ClangFormatCategory));
static cl::opt<bool> Inplace("i",
@@ -98,11 +113,22 @@ static cl::opt<unsigned>
"clang-format from an editor integration"),
cl::init(0), cl::cat(ClangFormatCategory));
-static cl::opt<bool> SortIncludes(
- "sort-includes",
- cl::desc("If set, overrides the include sorting behavior determined by the "
- "SortIncludes style flag"),
- cl::cat(ClangFormatCategory));
+static cl::opt<bool>
+ SortIncludes("sort-includes",
+ cl::desc("If set, overrides the include sorting behavior\n"
+ "determined by the SortIncludes style flag"),
+ cl::cat(ClangFormatCategory));
+
+static cl::opt<std::string> QualifierAlignment(
+ "qualifier-alignment",
+ cl::desc("If set, overrides the qualifier alignment style\n"
+ "determined by the QualifierAlignment style flag"),
+ cl::init(""), cl::cat(ClangFormatCategory));
+
+static cl::opt<std::string> Files(
+ "files",
+ cl::desc("A file containing a list of files to process, one per line."),
+ cl::value_desc("filename"), cl::init(""), cl::cat(ClangFormatCategory));
static cl::opt<bool>
Verbose("verbose", cl::desc("If set, shows the list of processed files"),
@@ -135,8 +161,9 @@ static cl::opt<bool>
static cl::opt<unsigned> ErrorLimit(
"ferror-limit",
- cl::desc("Set the maximum number of clang-format errors to emit before "
- "stopping (0 = no limit). Used only with --dry-run or -n"),
+ cl::desc("Set the maximum number of clang-format errors to emit\n"
+ "before stopping (0 = no limit).\n"
+ "Used only with --dry-run or -n"),
cl::init(0), cl::cat(ClangFormatCategory));
static cl::opt<bool>
@@ -220,8 +247,12 @@ static bool fillRanges(MemoryBuffer *Code,
errs() << "error: invalid <start line>:<end line> pair\n";
return true;
}
+ if (FromLine < 1) {
+ errs() << "error: start line should be at least 1\n";
+ return true;
+ }
if (FromLine > ToLine) {
- errs() << "error: start line should be less than end line\n";
+ errs() << "error: start line should not exceed end line\n";
return true;
}
SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1);
@@ -345,14 +376,27 @@ static void outputXML(const Replacements &Replaces,
if (!Status.FormatComplete)
outs() << " line='" << Status.Line << "'";
outs() << ">\n";
- if (Cursor.getNumOccurrences() != 0)
+ if (Cursor.getNumOccurrences() != 0) {
outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition)
<< "</cursor>\n";
+ }
outputReplacementsXML(Replaces);
outs() << "</replacements>\n";
}
+class ClangFormatDiagConsumer : public DiagnosticConsumer {
+ virtual void anchor() {}
+
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
+
+ SmallVector<char, 16> vec;
+ Info.FormatDiagnostic(vec);
+ errs() << "clang-format error:" << vec << "\n";
+ }
+};
+
// Returns true on error.
static bool format(StringRef FileName) {
if (!OutputXML && Inplace && FileName == "-") {
@@ -402,6 +446,27 @@ static bool format(StringRef FileName) {
return true;
}
+ StringRef QualifierAlignmentOrder = QualifierAlignment;
+
+ FormatStyle->QualifierAlignment =
+ StringSwitch<FormatStyle::QualifierAlignmentStyle>(
+ QualifierAlignmentOrder.lower())
+ .Case("right", FormatStyle::QAS_Right)
+ .Case("left", FormatStyle::QAS_Left)
+ .Default(FormatStyle->QualifierAlignment);
+
+ if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) {
+ FormatStyle->QualifierOrder = {"const", "volatile", "type"};
+ } else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) {
+ FormatStyle->QualifierOrder = {"type", "const", "volatile"};
+ } else if (QualifierAlignmentOrder.contains("type")) {
+ FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom;
+ SmallVector<StringRef> Qualifiers;
+ QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
+ FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()};
+ }
+
if (SortIncludes.getNumOccurrences() != 0) {
if (SortIncludes)
FormatStyle->SortIncludes = FormatStyle::SI_CaseSensitive;
@@ -414,12 +479,11 @@ static bool format(StringRef FileName) {
// To format JSON insert a variable to trick the code into thinking its
// JavaScript.
- if (FormatStyle->isJson()) {
+ if (FormatStyle->isJson() && !FormatStyle->DisableFormat) {
auto Err = Replaces.add(tooling::Replacement(
tooling::Replacement(AssumedFileName, 0, 0, "x = ")));
- if (Err) {
+ if (Err)
llvm::errs() << "Bad Json variable insertion\n";
- }
}
auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces);
@@ -434,18 +498,20 @@ static bool format(StringRef FileName) {
reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status);
Replaces = Replaces.merge(FormatChanges);
if (OutputXML || DryRun) {
- if (DryRun) {
+ if (DryRun)
return emitReplacementWarnings(Replaces, AssumedFileName, Code);
- } else {
+ else
outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition);
- }
} else {
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
new llvm::vfs::InMemoryFileSystem);
FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+ ClangFormatDiagConsumer IgnoreDiagnostics;
DiagnosticsEngine Diagnostics(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
- new DiagnosticOptions);
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+ &IgnoreDiagnostics, false);
SourceManager Sources(Diagnostics, Files);
FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files,
InMemoryFileSystem.get());
@@ -530,8 +596,18 @@ int main(int argc, const char **argv) {
return 0;
}
- if (DumpConfig) {
+ if (DumpConfig)
return dumpConfig();
+
+ if (!Files.empty()) {
+ std::ifstream ExternalFileOfFiles{std::string(Files)};
+ std::string Line;
+ unsigned LineNo = 1;
+ while (std::getline(ExternalFileOfFiles, Line)) {
+ FileNames.push_back(Line);
+ LineNo++;
+ }
+ errs() << "Clang-formating " << LineNo << " files\n";
}
bool Error = false;
@@ -545,9 +621,13 @@ int main(int argc, const char **argv) {
"single file.\n";
return 1;
}
+
+ unsigned FileNo = 1;
for (const auto &FileName : FileNames) {
- if (Verbose)
- errs() << "Formatting " << FileName << "\n";
+ if (Verbose) {
+ errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] "
+ << FileName << "\n";
+ }
Error |= clang::format::format(FileName);
}
return Error ? 1 : 0;
diff --git a/gnu/llvm/clang/tools/clang-format/clang-format-diff.py b/gnu/llvm/clang/tools/clang-format/clang-format-diff.py
index ea483f59e96..1f6ff0fe295 100755
--- a/gnu/llvm/clang/tools/clang-format/clang-format-diff.py
+++ b/gnu/llvm/clang/tools/clang-format/clang-format-diff.py
@@ -47,8 +47,8 @@ def main():
help='custom pattern selecting file paths to reformat '
'(case sensitive, overrides -iregex)')
parser.add_argument('-iregex', metavar='PATTERN', default=
- r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hh|hpp|hxx|m|mm|inc|js|ts'
- r'|proto|protodevel|java|cs|json)',
+ r'.*\.(cpp|cc|c\+\+|cxx|cppm|ccm|cxxm|c\+\+m|c|cl|h|hh|hpp|hxx'
+ r'|m|mm|inc|js|ts|proto|protodevel|java|cs|json)',
help='custom pattern selecting file paths to reformat '
'(case insensitive, overridden by -regex)')
parser.add_argument('-sort-includes', action='store_true', default=False,
@@ -58,6 +58,11 @@ def main():
parser.add_argument('-style',
help='formatting style to apply (LLVM, GNU, Google, Chromium, '
'Microsoft, Mozilla, WebKit)')
+ parser.add_argument('-fallback-style',
+ help='The name of the predefined style used as a'
+ 'fallback in case clang-format is invoked with'
+ '-style=file, but can not find the .clang-format'
+ 'file to use.')
parser.add_argument('-binary', default='clang-format',
help='location of binary to use for clang-format')
args = parser.parse_args()
@@ -85,9 +90,11 @@ def main():
line_count = 1
if match.group(3):
line_count = int(match.group(3))
- if line_count == 0:
- continue
- end_line = start_line + line_count - 1
+ # Also format lines range if line_count is 0 in case of deleting
+ # surrounding statements.
+ end_line = start_line
+ if line_count != 0:
+ end_line += line_count - 1
lines_by_file.setdefault(filename, []).extend(
['-lines', str(start_line) + ':' + str(end_line)])
@@ -103,6 +110,8 @@ def main():
command.extend(lines)
if args.style:
command.extend(['-style', args.style])
+ if args.fallback_style:
+ command.extend(['-fallback-style', args.fallback_style])
try:
p = subprocess.Popen(command,
diff --git a/gnu/llvm/clang/tools/clang-format/clang-format.el b/gnu/llvm/clang/tools/clang-format/clang-format.el
index 768acb3a5d0..4e6daa82d4a 100644
--- a/gnu/llvm/clang/tools/clang-format/clang-format.el
+++ b/gnu/llvm/clang/tools/clang-format/clang-format.el
@@ -147,7 +147,7 @@ uses the function `buffer-file-name'."
(setq style clang-format-style))
(unless assume-file-name
- (setq assume-file-name buffer-file-name))
+ (setq assume-file-name (buffer-file-name (buffer-base-buffer))))
(let ((file-start (clang-format--bufferpos-to-filepos start 'approximate
'utf-8-unix))
diff --git a/gnu/llvm/clang/tools/clang-format/clang-format.py b/gnu/llvm/clang/tools/clang-format/clang-format.py
index 76fedb64814..7933dbcfadd 100644
--- a/gnu/llvm/clang/tools/clang-format/clang-format.py
+++ b/gnu/llvm/clang/tools/clang-format/clang-format.py
@@ -10,9 +10,9 @@
# imap <C-I> <c-o>:py3f <path-to-this-file>/clang-format.py<cr>
# endif
#
-# The if-elseif-endif conditional should pick either the python3 or python2
+# The if-elseif-endif conditional should pick either the python3 or python2
# integration depending on your vim setup.
-#
+#
# The first mapping enables clang-format for NORMAL and VISUAL mode, the second
# mapping adds support for INSERT mode. Change "C-I" to another binding if you
# need clang-format on a different key (C-I stands for Ctrl+i).
@@ -41,6 +41,7 @@ from __future__ import absolute_import, division, print_function
import difflib
import json
+import os.path
import platform
import subprocess
import sys
@@ -76,7 +77,8 @@ def main():
# Determine range to format.
if vim.eval('exists("l:lines")') == '1':
lines = ['-lines', vim.eval('l:lines')]
- elif vim.eval('exists("l:formatdiff")') == '1':
+ elif vim.eval('exists("l:formatdiff")') == '1' and \
+ os.path.exists(vim.current.buffer.name):
with open(vim.current.buffer.name, 'r') as f:
ondisk = f.read().splitlines();
sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer)
@@ -134,7 +136,7 @@ def main():
)
else:
header, content = stdout.split(b'\n', 1)
- header = json.loads(header)
+ header = json.loads(header.decode('utf-8'))
# Strip off the trailing newline (added above).
# This maintains trailing empty lines present in the buffer if
# the -lines specification requests them to remain unchanged.
diff --git a/gnu/llvm/clang/tools/clang-format/git-clang-format b/gnu/llvm/clang/tools/clang-format/git-clang-format
index 0233ceb3a86..054978c3dbd 100755
--- a/gnu/llvm/clang/tools/clang-format/git-clang-format
+++ b/gnu/llvm/clang/tools/clang-format/git-clang-format
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
#===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===#
#
@@ -32,12 +32,23 @@ import re
import subprocess
import sys
-usage = 'git clang-format [OPTIONS] [<commit>] [<commit>] [--] [<file>...]'
+usage = ('git clang-format [OPTIONS] [<commit>] [<commit>|--staged] '
+ '[--] [<file>...]')
desc = '''
If zero or one commits are given, run clang-format on all lines that differ
between the working directory and <commit>, which defaults to HEAD. Changes are
-only applied to the working directory.
+only applied to the working directory, or in the stage/index.
+
+Examples:
+ To format staged changes, i.e everything that's been `git add`ed:
+ git clang-format
+
+ To also format everything touched in the most recent commit:
+ git clang-format HEAD~1
+
+ If you're on a branch off main, to format everything touched on your branch:
+ git clang-format main
If two commits are given (requires --diff), run clang-format on all lines in the
second <commit> that differ from the first <commit>.
@@ -77,7 +88,8 @@ def main():
'c', 'h', # C
'm', # ObjC
'mm', # ObjC++
- 'cc', 'cp', 'cpp', 'c++', 'cxx', 'hh', 'hpp', 'hxx', # C++
+ 'cc', 'cp', 'cpp', 'c++', 'cxx', 'hh', 'hpp', 'hxx', 'inc', # C++
+ 'ccm', 'cppm', 'cxxm', 'c++m', # C++ Modules
'cu', 'cuh', # CUDA
# Other languages that clang-format supports
'proto', 'protodevel', # Protocol Buffers
@@ -99,6 +111,8 @@ def main():
help='default commit to use if none is specified'),
p.add_argument('--diff', action='store_true',
help='print a diff instead of applying the changes')
+ p.add_argument('--diffstat', action='store_true',
+ help='print a diffstat instead of applying the changes')
p.add_argument('--extensions',
default=config.get('clangformat.extensions',
default_extensions),
@@ -110,6 +124,8 @@ def main():
help='select hunks interactively')
p.add_argument('-q', '--quiet', action='count', default=0,
help='print less information')
+ p.add_argument('--staged', '--cached', action='store_true',
+ help='format lines in the stage instead of the working dir')
p.add_argument('--style',
default=config.get('clangformat.style', None),
help='passed to clang-format'),
@@ -129,12 +145,14 @@ def main():
commits, files = interpret_args(opts.args, dash_dash, opts.commit)
if len(commits) > 1:
+ if opts.staged:
+ die('--staged is not allowed when two commits are given')
if not opts.diff:
die('--diff is required when two commits are given')
else:
if len(commits) > 2:
die('at most two commits allowed; %d given' % len(commits))
- changed_lines = compute_diff_and_extract_lines(commits, files)
+ changed_lines = compute_diff_and_extract_lines(commits, files, opts.staged)
if opts.verbose >= 1:
ignored_files = set(changed_lines)
filter_by_extension(changed_lines, opts.extensions.lower().split(','))
@@ -153,36 +171,47 @@ def main():
print('Running clang-format on the following files:')
for filename in changed_lines:
print(' %s' % filename)
+
if not changed_lines:
if opts.verbose >= 0:
print('no modified files to format')
- return
+ return 0
+
if len(commits) > 1:
old_tree = commits[1]
- new_tree = run_clang_format_and_save_to_tree(changed_lines,
- revision=commits[1],
- binary=opts.binary,
- style=opts.style)
+ revision = old_tree
+ elif opts.staged:
+ old_tree = create_tree_from_index(changed_lines)
+ revision = ''
else:
old_tree = create_tree_from_workdir(changed_lines)
- new_tree = run_clang_format_and_save_to_tree(changed_lines,
- binary=opts.binary,
- style=opts.style)
+ revision = None
+ new_tree = run_clang_format_and_save_to_tree(changed_lines,
+ revision,
+ binary=opts.binary,
+ style=opts.style)
if opts.verbose >= 1:
print('old tree: %s' % old_tree)
print('new tree: %s' % new_tree)
+
if old_tree == new_tree:
if opts.verbose >= 0:
print('clang-format did not modify any files')
- elif opts.diff:
- print_diff(old_tree, new_tree)
- else:
- changed_files = apply_changes(old_tree, new_tree, force=opts.force,
- patch_mode=opts.patch)
- if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1:
- print('changed files:')
- for filename in changed_files:
- print(' %s' % filename)
+ return 0
+
+ if opts.diff:
+ return print_diff(old_tree, new_tree)
+ if opts.diffstat:
+ return print_diffstat(old_tree, new_tree)
+
+ changed_files = apply_changes(old_tree, new_tree, force=opts.force,
+ patch_mode=opts.patch)
+ if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1:
+ print('changed files:')
+ for filename in changed_files:
+ print(' %s' % filename)
+
+ return 1
def load_git_config(non_string_options=None):
@@ -271,9 +300,9 @@ def get_object_type(value):
return convert_string(stdout.strip())
-def compute_diff_and_extract_lines(commits, files):
+def compute_diff_and_extract_lines(commits, files, staged):
"""Calls compute_diff() followed by extract_lines()."""
- diff_process = compute_diff(commits, files)
+ diff_process = compute_diff(commits, files, staged)
changed_lines = extract_lines(diff_process.stdout)
diff_process.stdout.close()
diff_process.wait()
@@ -283,17 +312,21 @@ def compute_diff_and_extract_lines(commits, files):
return changed_lines
-def compute_diff(commits, files):
+def compute_diff(commits, files, staged):
"""Return a subprocess object producing the diff from `commits`.
The return value's `stdin` file object will produce a patch with the
- differences between the working directory and the first commit if a single
- one was specified, or the difference between both specified commits, filtered
- on `files` (if non-empty). Zero context lines are used in the patch."""
+ differences between the working directory (or stage if --staged is used) and
+ the first commit if a single one was specified, or the difference between
+ both specified commits, filtered on `files` (if non-empty).
+ Zero context lines are used in the patch."""
git_tool = 'diff-index'
+ extra_args = []
if len(commits) > 1:
git_tool = 'diff-tree'
- cmd = ['git', git_tool, '-p', '-U0'] + commits + ['--']
+ elif staged:
+ extra_args += ['--cached']
+ cmd = ['git', git_tool, '-p', '-U0'] + extra_args + commits + ['--']
cmd.extend(files)
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.stdin.close()
@@ -321,8 +354,11 @@ def extract_lines(patch_file):
line_count = 1
if match.group(3):
line_count = int(match.group(3))
- if line_count > 0:
- matches.setdefault(filename, []).append(Range(start_line, line_count))
+ if line_count == 0:
+ line_count = 1
+ if start_line == 0:
+ continue
+ matches.setdefault(filename, []).append(Range(start_line, line_count))
return matches
@@ -360,11 +396,29 @@ def create_tree_from_workdir(filenames):
return create_tree(filenames, '--stdin')
+def create_tree_from_index(filenames):
+ # Copy the environment, because the files have to be read from the original
+ # index.
+ env = os.environ.copy()
+ def index_contents_generator():
+ for filename in filenames:
+ git_ls_files_cmd = ['git', 'ls-files', '--stage', '-z', '--', filename]
+ git_ls_files = subprocess.Popen(git_ls_files_cmd, env=env,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ stdout = git_ls_files.communicate()[0]
+ yield convert_string(stdout.split(b'\0')[0])
+ return create_tree(index_contents_generator(), '--index-info')
+
+
def run_clang_format_and_save_to_tree(changed_lines, revision=None,
binary='clang-format', style=None):
"""Run clang-format on each file and save the result to a git tree.
Returns the object ID (SHA-1) of the created tree."""
+ # Copy the environment when formatting the files in the index, because the
+ # files have to be read from the original index.
+ env = os.environ.copy() if revision == '' else None
def iteritems(container):
try:
return container.iteritems() # Python 2
@@ -372,11 +426,15 @@ def run_clang_format_and_save_to_tree(changed_lines, revision=None,
return container.items() # Python 3
def index_info_generator():
for filename, line_ranges in iteritems(changed_lines):
- if revision:
- git_metadata_cmd = ['git', 'ls-tree',
- '%s:%s' % (revision, os.path.dirname(filename)),
- os.path.basename(filename)]
- git_metadata = subprocess.Popen(git_metadata_cmd, stdin=subprocess.PIPE,
+ if revision is not None:
+ if len(revision) > 0:
+ git_metadata_cmd = ['git', 'ls-tree',
+ '%s:%s' % (revision, os.path.dirname(filename)),
+ os.path.basename(filename)]
+ else:
+ git_metadata_cmd = ['git', 'ls-files', '--stage', '--', filename]
+ git_metadata = subprocess.Popen(git_metadata_cmd, env=env,
+ stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
stdout = git_metadata.communicate()[0]
mode = oct(int(stdout.split()[0], 8))
@@ -388,7 +446,8 @@ def run_clang_format_and_save_to_tree(changed_lines, revision=None,
blob_id = clang_format_to_blob(filename, line_ranges,
revision=revision,
binary=binary,
- style=style)
+ style=style,
+ env=env)
yield '%s %s\t%s' % (mode, blob_id, filename)
return create_tree(index_info_generator(), '--index-info')
@@ -414,11 +473,12 @@ def create_tree(input_lines, mode):
def clang_format_to_blob(filename, line_ranges, revision=None,
- binary='clang-format', style=None):
+ binary='clang-format', style=None, env=None):
"""Run clang-format on the given file and save the result to a git blob.
Runs on the file in `revision` if not None, or on the file in the working
- directory if `revision` is None.
+ directory if `revision` is None. Revision can be set to an empty string to run
+ clang-format on the file in the index.
Returns the object ID (SHA-1) of the created blob."""
clang_format_cmd = [binary]
@@ -427,10 +487,10 @@ def clang_format_to_blob(filename, line_ranges, revision=None,
clang_format_cmd.extend([
'-lines=%s:%s' % (start_line, start_line+line_count-1)
for start_line, line_count in line_ranges])
- if revision:
+ if revision is not None:
clang_format_cmd.extend(['-assume-filename='+filename])
git_show_cmd = ['git', 'cat-file', 'blob', '%s:%s' % (revision, filename)]
- git_show = subprocess.Popen(git_show_cmd, stdin=subprocess.PIPE,
+ git_show = subprocess.Popen(git_show_cmd, env=env, stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
git_show.stdin.close()
clang_format_stdin = git_show.stdout
@@ -502,9 +562,20 @@ def print_diff(old_tree, new_tree):
# We also only print modified files since `new_tree` only contains the files
# that were modified, so unmodified files would show as deleted without the
# filter.
- subprocess.check_call(['git', 'diff', '--diff-filter=M', old_tree, new_tree,
- '--'])
+ return subprocess.run(['git', 'diff', '--diff-filter=M',
+ '--exit-code', old_tree, new_tree]).returncode
+def print_diffstat(old_tree, new_tree):
+ """Print the diffstat between the two trees to stdout."""
+ # We use the porcelain 'diff' and not plumbing 'diff-tree' because the output
+ # is expected to be viewed by the user, and only the former does nice things
+ # like color and pagination.
+ #
+ # We also only print modified files since `new_tree` only contains the files
+ # that were modified, so unmodified files would show as deleted without the
+ # filter.
+ return subprocess.run(['git', 'diff', '--diff-filter=M', '--exit-code',
+ '--stat', old_tree, new_tree]).returncode
def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
"""Apply the changes in `new_tree` to the working directory.
@@ -530,7 +601,7 @@ def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
# better message, "Apply ... to index and worktree". This is not quite
# right, since it won't be applied to the user's index, but oh well.
with temporary_index_file(old_tree):
- subprocess.check_call(['git', 'checkout', '--patch', new_tree])
+ subprocess.run(['git', 'checkout', '--patch', new_tree], check=True)
index_tree = old_tree
else:
with temporary_index_file(new_tree):
@@ -593,4 +664,4 @@ def convert_string(bytes_input):
return str(bytes_input)
if __name__ == '__main__':
- main()
+ sys.exit(main())
diff --git a/gnu/llvm/clang/tools/clang-fuzzer/CMakeLists.txt b/gnu/llvm/clang/tools/clang-fuzzer/CMakeLists.txt
index 4b2243c5ceb..e68ed8bbcb0 100644
--- a/gnu/llvm/clang/tools/clang-fuzzer/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-fuzzer/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} FuzzMutate)
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} FuzzerCLI)
set(CXX_FLAGS_NOFUZZ ${CMAKE_CXX_FLAGS})
set(DUMMY_MAIN DummyClangFuzzer.cpp)
if(LLVM_LIB_FUZZING_ENGINE)
@@ -109,6 +109,7 @@ endif()
add_clang_subdirectory(handle-cxx)
add_clang_subdirectory(handle-llvm)
+add_clang_subdirectory(dictionary)
add_clang_executable(clang-fuzzer
EXCLUDE_FROM_ALL
diff --git a/gnu/llvm/clang/tools/clang-fuzzer/dictionary/CMakeLists.txt b/gnu/llvm/clang/tools/clang-fuzzer/dictionary/CMakeLists.txt
new file mode 100644
index 00000000000..ee4aa587ea5
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-fuzzer/dictionary/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_clang_executable(clang-fuzzer-dictionary
+ dictionary.c
+ )
+
diff --git a/gnu/llvm/clang/tools/clang-fuzzer/dictionary/dictionary.c b/gnu/llvm/clang/tools/clang-fuzzer/dictionary/dictionary.c
new file mode 100644
index 00000000000..90490477f70
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-fuzzer/dictionary/dictionary.c
@@ -0,0 +1,57 @@
+//===-- dictionary.c - Generate fuzzing dictionary for clang --------------===//
+//
+// 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 binary emits a fuzzing dictionary describing strings that are
+// significant to the clang parser: keywords and other tokens.
+//
+// The dictionary can be used by a fuzzer to reach interesting parser states
+// much more quickly.
+//
+// The output is a single-file dictionary supported by libFuzzer and AFL:
+// https://llvm.org/docs/LibFuzzer.html#dictionaries
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+static void emit(const char *Name, const char *Spelling) {
+ static char Hex[] = "0123456789abcdef";
+
+ printf("%s=\"", Name);
+ unsigned char C;
+ while ((C = *Spelling++)) {
+ if (C < 32 || C == '"' || C == '\\')
+ printf("\\x%c%c", Hex[C>>4], Hex[C%16]);
+ else
+ printf("%c", C);
+ }
+ printf("\"\n");
+}
+
+int main(int argc, char **argv) {
+#define PUNCTUATOR(Name, Spelling) emit(#Name, Spelling);
+#define KEYWORD(Name, Criteria) emit(#Name, #Name);
+#define PPKEYWORD(Name) emit(#Name, #Name);
+#define CXX_KEYWORD_OPERATOR(Name, Equivalent) emit(#Name, #Name);
+#define OBJC_AT_KEYWORD(Name) emit(#Name, #Name);
+#define ALIAS(Spelling, Equivalent, Criteria) emit(Spelling, Spelling);
+#include "clang/Basic/TokenKinds.def"
+ // Some other sub-token chunks significant to the lexer.
+ emit("ucn16", "\\u0000");
+ emit("ucn32", "\\U00000000");
+ emit("rawstart", "R\"(");
+ emit("rawend", ")\"");
+ emit("quote", "\"");
+ emit("squote", "'");
+ emit("u8quote", "u8\"");
+ emit("u16quote", "u\"");
+ emit("u32quote", "U\"");
+ emit("esc_nl", "\\\n");
+ emit("hex", "0x");
+}
+
diff --git a/gnu/llvm/clang/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp b/gnu/llvm/clang/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp
index 20cf98896e2..94f3b937d83 100644
--- a/gnu/llvm/clang/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp
+++ b/gnu/llvm/clang/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp
@@ -48,8 +48,6 @@ extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
initializeAnalysis(Registry);
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
- initializeAggressiveInstCombine(Registry);
- initializeInstrumentation(Registry);
initializeTarget(Registry);
CLArgs.push_back("-O2");
diff --git a/gnu/llvm/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt b/gnu/llvm/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt
index 6d62421d9a6..184d467b9c3 100644
--- a/gnu/llvm/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-fuzzer/handle-cxx/CMakeLists.txt
@@ -11,3 +11,5 @@ add_clang_library(clangHandleCXX
clangSerialization
clangTooling
)
+
+target_include_directories(clangHandleCXX PRIVATE .)
diff --git a/gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt b/gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt
index 9ceb1d33182..9962f9850f5 100644
--- a/gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/CMakeLists.txt
@@ -4,14 +4,17 @@ set(LLVM_LINK_COMPONENTS
Core
ExecutionEngine
IPO
+ IRPrinter
IRReader
MC
MCJIT
Object
+ Passes
RuntimeDyld
SelectionDAG
Support
Target
+ TargetParser
TransformUtils
native
)
diff --git a/gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp b/gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp
index 4adb6eb39d0..06df39dcdc4 100644
--- a/gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp
+++ b/gnu/llvm/clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp
@@ -30,47 +30,39 @@
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
+#include "llvm/IRPrinter/IRPrintingPasses.h"
#include "llvm/IRReader/IRReader.h"
-#include "llvm/Pass.h"
-#include "llvm/PassRegistry.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Passes/OptimizationLevel.h"
+#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Transforms/IPO.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#include "llvm/Transforms/Vectorize.h"
using namespace llvm;
-static codegen::RegisterCodeGenFlags CGF;
-
// Define a type for the functions that are compiled and executed
typedef void (*LLVMFunc)(int*, int*, int*, int);
// Helper function to parse command line args and find the optimization level
-static void getOptLevel(const std::vector<const char *> &ExtraArgs,
- CodeGenOpt::Level &OLvl) {
+static CodeGenOpt::Level
+getOptLevel(const std::vector<const char *> &ExtraArgs) {
// Find the optimization level from the command line args
- OLvl = CodeGenOpt::Default;
+ CodeGenOpt::Level OLvl = CodeGenOpt::Default;
for (auto &A : ExtraArgs) {
if (A[0] == '-' && A[1] == 'O') {
- switch(A[2]) {
- case '0': OLvl = CodeGenOpt::None; break;
- case '1': OLvl = CodeGenOpt::Less; break;
- case '2': OLvl = CodeGenOpt::Default; break;
- case '3': OLvl = CodeGenOpt::Aggressive; break;
- default:
- errs() << "error: opt level must be between 0 and 3.\n";
- std::exit(1);
+ if (auto Level = CodeGenOpt::parseLevel(A[2])) {
+ OLvl = *Level;
+ } else {
+ errs() << "error: opt level must be between 0 and 3.\n";
+ std::exit(1);
}
}
}
+ return OLvl;
}
static void ErrorAndExit(std::string message) {
@@ -80,16 +72,45 @@ static void ErrorAndExit(std::string message) {
// Helper function to add optimization passes to the TargetMachine at the
// specified optimization level, OptLevel
-static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
- CodeGenOpt::Level OptLevel,
- unsigned SizeLevel) {
- // Create and initialize a PassManagerBuilder
- PassManagerBuilder Builder;
- Builder.OptLevel = OptLevel;
- Builder.SizeLevel = SizeLevel;
- Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false);
- Builder.LoopVectorize = true;
- Builder.populateModulePassManager(MPM);
+static void RunOptimizationPasses(raw_ostream &OS, Module &M,
+ CodeGenOpt::Level OptLevel) {
+ llvm::OptimizationLevel OL;
+ switch (OptLevel) {
+ case CodeGenOpt::None:
+ OL = OptimizationLevel::O0;
+ break;
+ case CodeGenOpt::Less:
+ OL = OptimizationLevel::O1;
+ break;
+ case CodeGenOpt::Default:
+ OL = OptimizationLevel::O2;
+ break;
+ case CodeGenOpt::Aggressive:
+ OL = OptimizationLevel::O3;
+ break;
+ }
+
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+
+ PassBuilder PB;
+
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+ ModulePassManager MPM;
+ if (OL == OptimizationLevel::O0)
+ MPM = PB.buildO0DefaultPipeline(OL);
+ else
+ MPM = PB.buildPerModuleDefaultPipeline(OL);
+ MPM.addPass(PrintModulePass(OS));
+
+ MPM.run(M, MAM);
}
// Mimics the opt tool to run an optimization pass over the provided IR
@@ -120,26 +141,12 @@ static std::string OptLLVM(const std::string &IR, CodeGenOpt::Level OLvl) {
codegen::setFunctionAttributes(codegen::getCPUStr(),
codegen::getFeaturesStr(), *M);
- legacy::PassManager Passes;
-
- Passes.add(new TargetLibraryInfoWrapperPass(ModuleTriple));
- Passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
-
- LLVMTargetMachine &LTM = static_cast<LLVMTargetMachine &>(*TM);
- Passes.add(LTM.createPassConfig(Passes));
-
- Passes.add(createVerifierPass());
-
- AddOptimizationPasses(Passes, OLvl, 0);
-
// Add a pass that writes the optimized IR to an output stream
std::string outString;
raw_string_ostream OS(outString);
- Passes.add(createPrintModulePass(OS, "", false));
-
- Passes.run(*M);
+ RunOptimizationPasses(OS, *M, OLvl);
- return OS.str();
+ return outString;
}
// Takes a function and runs it on a set of inputs
@@ -216,8 +223,7 @@ void clang_fuzzer::HandleLLVM(const std::string &IR,
memcpy(UnoptArrays, InputArrays, kTotalSize);
// Parse ExtraArgs to set the optimization level
- CodeGenOpt::Level OLvl;
- getOptLevel(ExtraArgs, OLvl);
+ CodeGenOpt::Level OLvl = getOptLevel(ExtraArgs);
// First we optimize the IR by running a loop vectorizer pass
std::string OptIR = OptLLVM(IR, OLvl);
@@ -227,6 +233,4 @@ void clang_fuzzer::HandleLLVM(const std::string &IR,
if (memcmp(OptArrays, UnoptArrays, kTotalSize))
ErrorAndExit("!!!BUG!!!");
-
- return;
}
diff --git a/gnu/llvm/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt b/gnu/llvm/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt
index 339959b81af..baefc8a3014 100644
--- a/gnu/llvm/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt
@@ -14,6 +14,8 @@ add_clang_library(clangLoopProtoToCXX loop_proto_to_cxx.cpp
DEPENDS clangCXXLoopProto
LINK_LIBS clangCXXLoopProto ${PROTOBUF_LIBRARIES}
)
+target_include_directories(clangProtoToCXX PRIVATE .)
+target_include_directories(clangLoopProtoToCXX PRIVATE .)
add_clang_executable(clang-proto-to-cxx proto_to_cxx_main.cpp)
add_clang_executable(clang-loop-proto-to-cxx loop_proto_to_cxx_main.cpp)
diff --git a/gnu/llvm/clang/tools/clang-import-test/CMakeLists.txt b/gnu/llvm/clang/tools/clang-import-test/CMakeLists.txt
index e459de8f635..6b70bebd885 100644
--- a/gnu/llvm/clang/tools/clang-import-test/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-import-test/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
Core
Support
+ TargetParser
)
add_clang_executable(clang-import-test
diff --git a/gnu/llvm/clang/tools/clang-import-test/clang-import-test.cpp b/gnu/llvm/clang/tools/clang-import-test/clang-import-test.cpp
index a5206319bbb..6403d1120fd 100644
--- a/gnu/llvm/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/gnu/llvm/clang/tools/clang-import-test/clang-import-test.cpp
@@ -43,7 +43,7 @@ static llvm::cl::opt<std::string> Expression(
llvm::cl::desc("Path to a file containing the expression to parse"));
static llvm::cl::list<std::string>
- Imports("import", llvm::cl::ZeroOrMore,
+ Imports("import",
llvm::cl::desc("Path to a file containing declarations to import"));
static llvm::cl::opt<bool>
@@ -56,7 +56,7 @@ static llvm::cl::opt<bool> UseOrigins(
"Use DeclContext origin information for more accurate lookups"));
static llvm::cl::list<std::string>
- ClangArgs("Xcc", llvm::cl::ZeroOrMore,
+ ClangArgs("Xcc",
llvm::cl::desc("Argument to pass to the CompilerInvocation"),
llvm::cl::CommaSeparated);
@@ -84,18 +84,18 @@ public:
TestDiagnosticConsumer()
: Passthrough(std::make_unique<TextDiagnosticBuffer>()) {}
- virtual void BeginSourceFile(const LangOptions &LangOpts,
- const Preprocessor *PP = nullptr) override {
+ void BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP = nullptr) override {
this->LangOpts = &LangOpts;
return Passthrough->BeginSourceFile(LangOpts, PP);
}
- virtual void EndSourceFile() override {
+ void EndSourceFile() override {
this->LangOpts = nullptr;
Passthrough->EndSourceFile();
}
- virtual bool IncludeInDiagnosticCounts() const override {
+ bool IncludeInDiagnosticCounts() const override {
return Passthrough->IncludeInDiagnosticCounts();
}
@@ -130,8 +130,8 @@ private:
llvm::errs() << '\n';
}
- virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const Diagnostic &Info) override {
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
if (Info.hasSourceManager() && LangOpts) {
SourceManager &SM = Info.getSourceManager();
@@ -230,8 +230,9 @@ std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
llvm::LLVMContext &LLVMCtx) {
StringRef ModuleName("$__module");
return std::unique_ptr<CodeGenerator>(CreateLLVMCodeGen(
- CI.getDiagnostics(), ModuleName, CI.getHeaderSearchOpts(),
- CI.getPreprocessorOpts(), CI.getCodeGenOpts(), LLVMCtx));
+ CI.getDiagnostics(), ModuleName, &CI.getVirtualFileSystem(),
+ CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
+ LLVMCtx));
}
} // namespace init_convenience
diff --git a/gnu/llvm/clang/tools/clang-linker-wrapper/CMakeLists.txt b/gnu/llvm/clang/tools/clang-linker-wrapper/CMakeLists.txt
new file mode 100644
index 00000000000..cf0774c8c6c
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-linker-wrapper/CMakeLists.txt
@@ -0,0 +1,45 @@
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ BitWriter
+ Core
+ BinaryFormat
+ MC
+ Target
+ TransformUtils
+ Analysis
+ Passes
+ IRReader
+ Object
+ Option
+ Support
+ TargetParser
+ CodeGen
+ LTO
+ )
+
+set(LLVM_TARGET_DEFINITIONS LinkerWrapperOpts.td)
+tablegen(LLVM LinkerWrapperOpts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(LinkerWrapperOpts)
+
+if(NOT CLANG_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen LinkerWrapperOpts)
+endif()
+
+add_clang_tool(clang-linker-wrapper
+ ClangLinkerWrapper.cpp
+ OffloadWrapper.cpp
+
+ DEPENDS
+ ${tablegen_deps}
+ )
+
+set(CLANG_LINKER_WRAPPER_LIB_DEPS
+ clangBasic
+ )
+
+add_dependencies(clang clang-linker-wrapper)
+
+target_link_libraries(clang-linker-wrapper
+ PRIVATE
+ ${CLANG_LINKER_WRAPPER_LIB_DEPS}
+ )
diff --git a/gnu/llvm/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/gnu/llvm/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
new file mode 100644
index 00000000000..16ac5f4c8be
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -0,0 +1,1442 @@
+//===-- clang-linker-wrapper/ClangLinkerWrapper.cpp - wrapper over linker-===//
+//
+// 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 tool works as a wrapper over a linking job. This tool is used to create
+// linked device images for offloading. It scans the linker's input for embedded
+// device offloading data stored in sections `.llvm.offloading` and extracts it
+// as a temporary file. The extracted device files will then be passed to a
+// device linking job to create a final device image.
+//
+//===---------------------------------------------------------------------===//
+
+#include "OffloadWrapper.h"
+#include "clang/Basic/Version.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/OffloadBinary.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include <atomic>
+#include <optional>
+
+using namespace llvm;
+using namespace llvm::opt;
+using namespace llvm::object;
+
+/// Path of the current binary.
+static const char *LinkerExecutable;
+
+/// Ssave intermediary results.
+static bool SaveTemps = false;
+
+/// Print arguments without executing.
+static bool DryRun = false;
+
+/// Print verbose output.
+static bool Verbose = false;
+
+/// Filename of the executable being created.
+static StringRef ExecutableName;
+
+/// Binary path for the CUDA installation.
+static std::string CudaBinaryPath;
+
+/// Mutex lock to protect writes to shared TempFiles in parallel.
+static std::mutex TempFilesMutex;
+
+/// Temporary files created by the linker wrapper.
+static std::list<SmallString<128>> TempFiles;
+
+/// Codegen flags for LTO backend.
+static codegen::RegisterCodeGenFlags CodeGenFlags;
+
+/// Global flag to indicate that the LTO pipeline threw an error.
+static std::atomic<bool> LTOError;
+
+using OffloadingImage = OffloadBinary::OffloadingImage;
+
+namespace llvm {
+// Provide DenseMapInfo so that OffloadKind can be used in a DenseMap.
+template <> struct DenseMapInfo<OffloadKind> {
+ static inline OffloadKind getEmptyKey() { return OFK_LAST; }
+ static inline OffloadKind getTombstoneKey() {
+ return static_cast<OffloadKind>(OFK_LAST + 1);
+ }
+ static unsigned getHashValue(const OffloadKind &Val) { return Val; }
+
+ static bool isEqual(const OffloadKind &LHS, const OffloadKind &RHS) {
+ return LHS == RHS;
+ }
+};
+} // namespace llvm
+
+namespace {
+using std::error_code;
+
+/// Must not overlap with llvm::opt::DriverFlag.
+enum WrapperFlags {
+ WrapperOnlyOption = (1 << 4), // Options only used by the linker wrapper.
+ DeviceOnlyOption = (1 << 5), // Options only used for device linking.
+};
+
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "LinkerWrapperOpts.inc"
+ LastOption
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
+#include "LinkerWrapperOpts.inc"
+#undef PREFIX
+
+static constexpr OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
+#include "LinkerWrapperOpts.inc"
+#undef OPTION
+};
+
+class WrapperOptTable : public opt::GenericOptTable {
+public:
+ WrapperOptTable() : opt::GenericOptTable(InfoTable) {}
+};
+
+const OptTable &getOptTable() {
+ static const WrapperOptTable *Table = []() {
+ auto Result = std::make_unique<WrapperOptTable>();
+ return Result.release();
+ }();
+ return *Table;
+}
+
+void printCommands(ArrayRef<StringRef> CmdArgs) {
+ if (CmdArgs.empty())
+ return;
+
+ llvm::errs() << " \"" << CmdArgs.front() << "\" ";
+ for (auto IC = std::next(CmdArgs.begin()), IE = CmdArgs.end(); IC != IE; ++IC)
+ llvm::errs() << *IC << (std::next(IC) != IE ? " " : "\n");
+}
+
+[[noreturn]] void reportError(Error E) {
+ outs().flush();
+ logAllUnhandledErrors(std::move(E),
+ WithColor::error(errs(), LinkerExecutable));
+ exit(EXIT_FAILURE);
+}
+
+/// Create an extra user-specified \p OffloadFile.
+/// TODO: We should find a way to wrap these as libraries instead.
+Expected<OffloadFile> getInputBitcodeLibrary(StringRef Input) {
+ auto [Device, Path] = StringRef(Input).split('=');
+ auto [String, Arch] = Device.rsplit('-');
+ auto [Kind, Triple] = String.split('-');
+
+ llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> ImageOrError =
+ llvm::MemoryBuffer::getFileOrSTDIN(Path);
+ if (std::error_code EC = ImageOrError.getError())
+ return createFileError(Path, EC);
+
+ OffloadingImage Image{};
+ Image.TheImageKind = IMG_Bitcode;
+ Image.TheOffloadKind = getOffloadKind(Kind);
+ Image.StringData = {{"triple", Triple}, {"arch", Arch}};
+ Image.Image = std::move(*ImageOrError);
+
+ std::unique_ptr<MemoryBuffer> Binary = OffloadBinary::write(Image);
+ auto NewBinaryOrErr = OffloadBinary::create(*Binary);
+ if (!NewBinaryOrErr)
+ return NewBinaryOrErr.takeError();
+ return OffloadFile(std::move(*NewBinaryOrErr), std::move(Binary));
+}
+
+std::string getMainExecutable(const char *Name) {
+ void *Ptr = (void *)(intptr_t)&getMainExecutable;
+ auto COWPath = sys::fs::getMainExecutable(Name, Ptr);
+ return sys::path::parent_path(COWPath).str();
+}
+
+/// Get a temporary filename suitable for output.
+Expected<StringRef> createOutputFile(const Twine &Prefix, StringRef Extension) {
+ std::scoped_lock<decltype(TempFilesMutex)> Lock(TempFilesMutex);
+ SmallString<128> OutputFile;
+ if (SaveTemps) {
+ (Prefix + "." + Extension).toNullTerminatedStringRef(OutputFile);
+ } else {
+ if (std::error_code EC =
+ sys::fs::createTemporaryFile(Prefix, Extension, OutputFile))
+ return createFileError(OutputFile, EC);
+ }
+
+ TempFiles.emplace_back(std::move(OutputFile));
+ return TempFiles.back();
+}
+
+/// Execute the command \p ExecutablePath with the arguments \p Args.
+Error executeCommands(StringRef ExecutablePath, ArrayRef<StringRef> Args) {
+ if (Verbose || DryRun)
+ printCommands(Args);
+
+ if (!DryRun)
+ if (sys::ExecuteAndWait(ExecutablePath, Args))
+ return createStringError(inconvertibleErrorCode(),
+ "'" + sys::path::filename(ExecutablePath) + "'" +
+ " failed");
+ return Error::success();
+}
+
+Expected<std::string> findProgram(StringRef Name, ArrayRef<StringRef> Paths) {
+
+ ErrorOr<std::string> Path = sys::findProgramByName(Name, Paths);
+ if (!Path)
+ Path = sys::findProgramByName(Name);
+ if (!Path && DryRun)
+ return Name.str();
+ if (!Path)
+ return createStringError(Path.getError(),
+ "Unable to find '" + Name + "' in path");
+ return *Path;
+}
+
+/// Runs the wrapped linker job with the newly created input.
+Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) {
+ llvm::TimeTraceScope TimeScope("Execute host linker");
+
+ // Render the linker arguments and add the newly created image. We add it
+ // after the output file to ensure it is linked with the correct libraries.
+ StringRef LinkerPath = Args.getLastArgValue(OPT_linker_path_EQ);
+ ArgStringList NewLinkerArgs;
+ for (const opt::Arg *Arg : Args) {
+ // Do not forward arguments only intended for the linker wrapper.
+ if (Arg->getOption().hasFlag(WrapperOnlyOption))
+ continue;
+
+ Arg->render(Args, NewLinkerArgs);
+ if (Arg->getOption().matches(OPT_o))
+ llvm::transform(Files, std::back_inserter(NewLinkerArgs),
+ [&](StringRef Arg) { return Args.MakeArgString(Arg); });
+ }
+
+ SmallVector<StringRef> LinkerArgs({LinkerPath});
+ for (StringRef Arg : NewLinkerArgs)
+ LinkerArgs.push_back(Arg);
+ if (Error Err = executeCommands(LinkerPath, LinkerArgs))
+ return Err;
+ return Error::success();
+}
+
+void printVersion(raw_ostream &OS) {
+ OS << clang::getClangToolFullVersion("clang-linker-wrapper") << '\n';
+}
+
+namespace nvptx {
+Expected<StringRef>
+fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles,
+ const ArgList &Args) {
+ llvm::TimeTraceScope TimeScope("NVPTX fatbinary");
+ // NVPTX uses the fatbinary program to bundle the linked images.
+ Expected<std::string> FatBinaryPath =
+ findProgram("fatbinary", {CudaBinaryPath + "/bin"});
+ if (!FatBinaryPath)
+ return FatBinaryPath.takeError();
+
+ llvm::Triple Triple(
+ Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
+
+ // Create a new file to write the linked device image to.
+ auto TempFileOrErr =
+ createOutputFile(sys::path::filename(ExecutableName), "fatbin");
+ if (!TempFileOrErr)
+ return TempFileOrErr.takeError();
+
+ SmallVector<StringRef, 16> CmdArgs;
+ CmdArgs.push_back(*FatBinaryPath);
+ CmdArgs.push_back(Triple.isArch64Bit() ? "-64" : "-32");
+ CmdArgs.push_back("--create");
+ CmdArgs.push_back(*TempFileOrErr);
+ for (const auto &[File, Arch] : InputFiles)
+ CmdArgs.push_back(
+ Args.MakeArgString("--image=profile=" + Arch + ",file=" + File));
+
+ if (Error Err = executeCommands(*FatBinaryPath, CmdArgs))
+ return std::move(Err);
+
+ return *TempFileOrErr;
+}
+} // namespace nvptx
+
+namespace amdgcn {
+Expected<StringRef>
+fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles,
+ const ArgList &Args) {
+ llvm::TimeTraceScope TimeScope("AMDGPU Fatbinary");
+
+ // AMDGPU uses the clang-offload-bundler to bundle the linked images.
+ Expected<std::string> OffloadBundlerPath = findProgram(
+ "clang-offload-bundler", {getMainExecutable("clang-offload-bundler")});
+ if (!OffloadBundlerPath)
+ return OffloadBundlerPath.takeError();
+
+ llvm::Triple Triple(
+ Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
+
+ // Create a new file to write the linked device image to.
+ auto TempFileOrErr =
+ createOutputFile(sys::path::filename(ExecutableName), "hipfb");
+ if (!TempFileOrErr)
+ return TempFileOrErr.takeError();
+
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+
+ SmallVector<StringRef, 16> CmdArgs;
+ CmdArgs.push_back(*OffloadBundlerPath);
+ CmdArgs.push_back("-type=o");
+ CmdArgs.push_back("-bundle-align=4096");
+
+ SmallVector<StringRef> Targets = {"-targets=host-x86_64-unknown-linux"};
+ for (const auto &[File, Arch] : InputFiles)
+ Targets.push_back(Saver.save("hipv4-amdgcn-amd-amdhsa--" + Arch));
+ CmdArgs.push_back(Saver.save(llvm::join(Targets, ",")));
+
+ CmdArgs.push_back("-input=/dev/null");
+ for (const auto &[File, Arch] : InputFiles)
+ CmdArgs.push_back(Saver.save("-input=" + File));
+
+ CmdArgs.push_back(Saver.save("-output=" + *TempFileOrErr));
+
+ if (Error Err = executeCommands(*OffloadBundlerPath, CmdArgs))
+ return std::move(Err);
+
+ return *TempFileOrErr;
+}
+} // namespace amdgcn
+
+namespace generic {
+Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args) {
+ llvm::TimeTraceScope TimeScope("Clang");
+ // Use `clang` to invoke the appropriate device tools.
+ Expected<std::string> ClangPath =
+ findProgram("clang", {getMainExecutable("clang")});
+ if (!ClangPath)
+ return ClangPath.takeError();
+
+ const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
+ StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
+ if (Arch.empty())
+ Arch = "native";
+ // Create a new file to write the linked device image to. Assume that the
+ // input filename already has the device and architecture.
+ auto TempFileOrErr =
+ createOutputFile(sys::path::filename(ExecutableName) + "." +
+ Triple.getArchName() + "." + Arch,
+ "img");
+ if (!TempFileOrErr)
+ return TempFileOrErr.takeError();
+
+ StringRef OptLevel = Args.getLastArgValue(OPT_opt_level, "O2");
+ SmallVector<StringRef, 16> CmdArgs{
+ *ClangPath,
+ "-o",
+ *TempFileOrErr,
+ Args.MakeArgString("--target=" + Triple.getTriple()),
+ Triple.isAMDGPU() ? Args.MakeArgString("-mcpu=" + Arch)
+ : Args.MakeArgString("-march=" + Arch),
+ Args.MakeArgString("-" + OptLevel),
+ "-Wl,--no-undefined",
+ };
+
+ // If this is CPU offloading we copy the input libraries.
+ if (!Triple.isAMDGPU() && !Triple.isNVPTX()) {
+ CmdArgs.push_back("-Bsymbolic");
+ CmdArgs.push_back("-shared");
+ ArgStringList LinkerArgs;
+ for (const opt::Arg *Arg :
+ Args.filtered(OPT_library, OPT_rpath, OPT_library_path))
+ Arg->render(Args, LinkerArgs);
+ llvm::copy(LinkerArgs, std::back_inserter(CmdArgs));
+ }
+
+ if (Args.hasArg(OPT_debug))
+ CmdArgs.push_back("-g");
+
+ if (SaveTemps)
+ CmdArgs.push_back("-save-temps");
+
+ if (Verbose)
+ CmdArgs.push_back("-v");
+
+ if (!CudaBinaryPath.empty())
+ CmdArgs.push_back(Args.MakeArgString("--cuda-path=" + CudaBinaryPath));
+
+ for (StringRef Arg : Args.getAllArgValues(OPT_ptxas_arg))
+ llvm::copy(SmallVector<StringRef>({"-Xcuda-ptxas", Arg}),
+ std::back_inserter(CmdArgs));
+
+ for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ))
+ CmdArgs.push_back(Args.MakeArgString("-Wl," + Arg));
+
+ for (StringRef InputFile : InputFiles)
+ CmdArgs.push_back(InputFile);
+
+ if (Error Err = executeCommands(*ClangPath, CmdArgs))
+ return std::move(Err);
+
+ return *TempFileOrErr;
+}
+} // namespace generic
+
+Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
+ const ArgList &Args) {
+ const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
+ switch (Triple.getArch()) {
+ case Triple::nvptx:
+ case Triple::nvptx64:
+ case Triple::amdgcn:
+ case Triple::x86:
+ case Triple::x86_64:
+ case Triple::aarch64:
+ case Triple::aarch64_be:
+ case Triple::ppc64:
+ case Triple::ppc64le:
+ return generic::clang(InputFiles, Args);
+ default:
+ return createStringError(inconvertibleErrorCode(),
+ Triple.getArchName() +
+ " linking is not supported");
+ }
+}
+
+void diagnosticHandler(const DiagnosticInfo &DI) {
+ std::string ErrStorage;
+ raw_string_ostream OS(ErrStorage);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+
+ switch (DI.getSeverity()) {
+ case DS_Error:
+ WithColor::error(errs(), LinkerExecutable) << ErrStorage << "\n";
+ LTOError = true;
+ break;
+ case DS_Warning:
+ WithColor::warning(errs(), LinkerExecutable) << ErrStorage << "\n";
+ break;
+ case DS_Note:
+ WithColor::note(errs(), LinkerExecutable) << ErrStorage << "\n";
+ break;
+ case DS_Remark:
+ WithColor::remark(errs()) << ErrStorage << "\n";
+ break;
+ }
+}
+
+// Get the list of target features from the input file and unify them such that
+// if there are multiple +xxx or -xxx features we only keep the last one.
+std::vector<std::string> getTargetFeatures(ArrayRef<OffloadFile> InputFiles) {
+ SmallVector<StringRef> Features;
+ for (const OffloadFile &File : InputFiles) {
+ for (auto Arg : llvm::split(File.getBinary()->getString("feature"), ","))
+ Features.emplace_back(Arg);
+ }
+
+ // Only add a feature if it hasn't been seen before starting from the end.
+ std::vector<std::string> UnifiedFeatures;
+ DenseSet<StringRef> UsedFeatures;
+ for (StringRef Feature : llvm::reverse(Features)) {
+ if (UsedFeatures.insert(Feature.drop_front()).second)
+ UnifiedFeatures.push_back(Feature.str());
+ }
+
+ return UnifiedFeatures;
+}
+
+template <typename ModuleHook = function_ref<bool(size_t, const Module &)>>
+std::unique_ptr<lto::LTO> createLTO(
+ const ArgList &Args, const std::vector<std::string> &Features,
+ ModuleHook Hook = [](size_t, const Module &) { return true; }) {
+ const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
+ StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
+ lto::Config Conf;
+ lto::ThinBackend Backend;
+ // TODO: Handle index-only thin-LTO
+ Backend =
+ lto::createInProcessThinBackend(llvm::heavyweight_hardware_concurrency());
+
+ Conf.CPU = Arch.str();
+ Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple);
+
+ StringRef OptLevel = Args.getLastArgValue(OPT_opt_level, "O2");
+ Conf.MAttrs = Features;
+ std::optional<CodeGenOpt::Level> CGOptLevelOrNone =
+ CodeGenOpt::parseLevel(OptLevel[1]);
+ assert(CGOptLevelOrNone && "Invalid optimization level");
+ Conf.CGOptLevel = *CGOptLevelOrNone;
+ Conf.OptLevel = OptLevel[1] - '0';
+ Conf.DefaultTriple = Triple.getTriple();
+
+ LTOError = false;
+ Conf.DiagHandler = diagnosticHandler;
+
+ Conf.PTO.LoopVectorization = Conf.OptLevel > 1;
+ Conf.PTO.SLPVectorization = Conf.OptLevel > 1;
+
+ if (SaveTemps) {
+ std::string TempName = (sys::path::filename(ExecutableName) + "." +
+ Triple.getTriple() + "." + Arch)
+ .str();
+ Conf.PostInternalizeModuleHook = [=](size_t Task, const Module &M) {
+ std::string File =
+ !Task ? TempName + ".postlink.bc"
+ : TempName + "." + std::to_string(Task) + ".postlink.bc";
+ error_code EC;
+ raw_fd_ostream LinkedBitcode(File, EC, sys::fs::OF_None);
+ if (EC)
+ reportError(errorCodeToError(EC));
+ WriteBitcodeToFile(M, LinkedBitcode);
+ return true;
+ };
+ Conf.PreCodeGenModuleHook = [=](size_t Task, const Module &M) {
+ std::string File =
+ !Task ? TempName + ".postopt.bc"
+ : TempName + "." + std::to_string(Task) + ".postopt.bc";
+ error_code EC;
+ raw_fd_ostream LinkedBitcode(File, EC, sys::fs::OF_None);
+ if (EC)
+ reportError(errorCodeToError(EC));
+ WriteBitcodeToFile(M, LinkedBitcode);
+ return true;
+ };
+ }
+ Conf.PostOptModuleHook = Hook;
+ Conf.CGFileType =
+ (Triple.isNVPTX() || SaveTemps) ? CGFT_AssemblyFile : CGFT_ObjectFile;
+
+ // TODO: Handle remark files
+ Conf.HasWholeProgramVisibility = Args.hasArg(OPT_whole_program);
+
+ return std::make_unique<lto::LTO>(std::move(Conf), Backend);
+}
+
+// Returns true if \p S is valid as a C language identifier and will be given
+// `__start_` and `__stop_` symbols.
+bool isValidCIdentifier(StringRef S) {
+ return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
+ llvm::all_of(llvm::drop_begin(S),
+ [](char C) { return C == '_' || isAlnum(C); });
+}
+
+Error linkBitcodeFiles(SmallVectorImpl<OffloadFile> &InputFiles,
+ SmallVectorImpl<StringRef> &OutputFiles,
+ const ArgList &Args) {
+ llvm::TimeTraceScope TimeScope("Link bitcode files");
+ const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
+ StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
+
+ SmallVector<OffloadFile, 4> BitcodeInputFiles;
+ DenseSet<StringRef> UsedInRegularObj;
+ DenseSet<StringRef> UsedInSharedLib;
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+
+ // Search for bitcode files in the input and create an LTO input file. If it
+ // is not a bitcode file, scan its symbol table for symbols we need to save.
+ for (OffloadFile &File : InputFiles) {
+ MemoryBufferRef Buffer = MemoryBufferRef(File.getBinary()->getImage(), "");
+
+ file_magic Type = identify_magic(Buffer.getBuffer());
+ switch (Type) {
+ case file_magic::bitcode: {
+ BitcodeInputFiles.emplace_back(std::move(File));
+ continue;
+ }
+ case file_magic::elf_relocatable:
+ case file_magic::elf_shared_object: {
+ Expected<std::unique_ptr<ObjectFile>> ObjFile =
+ ObjectFile::createObjectFile(Buffer);
+ if (!ObjFile)
+ continue;
+
+ for (SymbolRef Sym : (*ObjFile)->symbols()) {
+ Expected<StringRef> Name = Sym.getName();
+ if (!Name)
+ return Name.takeError();
+
+ // Record if we've seen these symbols in any object or shared libraries.
+ if ((*ObjFile)->isRelocatableObject())
+ UsedInRegularObj.insert(Saver.save(*Name));
+ else
+ UsedInSharedLib.insert(Saver.save(*Name));
+ }
+ continue;
+ }
+ default:
+ continue;
+ }
+ }
+
+ if (BitcodeInputFiles.empty())
+ return Error::success();
+
+ // Remove all the bitcode files that we moved from the original input.
+ llvm::erase_if(InputFiles, [](OffloadFile &F) { return !F.getBinary(); });
+
+ // LTO Module hook to output bitcode without running the backend.
+ SmallVector<StringRef, 4> BitcodeOutput;
+ auto OutputBitcode = [&](size_t, const Module &M) {
+ auto TempFileOrErr = createOutputFile(sys::path::filename(ExecutableName) +
+ "-jit-" + Triple.getTriple(),
+ "bc");
+ if (!TempFileOrErr)
+ reportError(TempFileOrErr.takeError());
+
+ std::error_code EC;
+ raw_fd_ostream LinkedBitcode(*TempFileOrErr, EC, sys::fs::OF_None);
+ if (EC)
+ reportError(errorCodeToError(EC));
+ WriteBitcodeToFile(M, LinkedBitcode);
+ BitcodeOutput.push_back(*TempFileOrErr);
+ return false;
+ };
+
+ // We assume visibility of the whole program if every input file was bitcode.
+ auto Features = getTargetFeatures(BitcodeInputFiles);
+ auto LTOBackend = Args.hasArg(OPT_embed_bitcode)
+ ? createLTO(Args, Features, OutputBitcode)
+ : createLTO(Args, Features);
+
+ // We need to resolve the symbols so the LTO backend knows which symbols need
+ // to be kept or can be internalized. This is a simplified symbol resolution
+ // scheme to approximate the full resolution a linker would do.
+ uint64_t Idx = 0;
+ DenseSet<StringRef> PrevailingSymbols;
+ for (auto &BitcodeInput : BitcodeInputFiles) {
+ // Get a semi-unique buffer identifier for Thin-LTO.
+ StringRef Identifier = Saver.save(
+ std::to_string(Idx++) + "." +
+ BitcodeInput.getBinary()->getMemoryBufferRef().getBufferIdentifier());
+ MemoryBufferRef Buffer =
+ MemoryBufferRef(BitcodeInput.getBinary()->getImage(), Identifier);
+ Expected<std::unique_ptr<lto::InputFile>> BitcodeFileOrErr =
+ llvm::lto::InputFile::create(Buffer);
+ if (!BitcodeFileOrErr)
+ return BitcodeFileOrErr.takeError();
+
+ // Save the input file and the buffer associated with its memory.
+ const auto Symbols = (*BitcodeFileOrErr)->symbols();
+ SmallVector<lto::SymbolResolution, 16> Resolutions(Symbols.size());
+ size_t Idx = 0;
+ for (auto &Sym : Symbols) {
+ lto::SymbolResolution &Res = Resolutions[Idx++];
+
+ // We will use this as the prevailing symbol definition in LTO unless
+ // it is undefined or another definition has already been used.
+ Res.Prevailing =
+ !Sym.isUndefined() &&
+ PrevailingSymbols.insert(Saver.save(Sym.getName())).second;
+
+ // We need LTO to preseve the following global symbols:
+ // 1) Symbols used in regular objects.
+ // 2) Sections that will be given a __start/__stop symbol.
+ // 3) Prevailing symbols that are needed visible to external libraries.
+ Res.VisibleToRegularObj =
+ UsedInRegularObj.contains(Sym.getName()) ||
+ isValidCIdentifier(Sym.getSectionName()) ||
+ (Res.Prevailing &&
+ (Sym.getVisibility() != GlobalValue::HiddenVisibility &&
+ !Sym.canBeOmittedFromSymbolTable()));
+
+ // Identify symbols that must be exported dynamically and can be
+ // referenced by other files.
+ Res.ExportDynamic =
+ Sym.getVisibility() != GlobalValue::HiddenVisibility &&
+ (UsedInSharedLib.contains(Sym.getName()) ||
+ !Sym.canBeOmittedFromSymbolTable());
+
+ // The final definition will reside in this linkage unit if the symbol is
+ // defined and local to the module. This only checks for bitcode files,
+ // full assertion will require complete symbol resolution.
+ Res.FinalDefinitionInLinkageUnit =
+ Sym.getVisibility() != GlobalValue::DefaultVisibility &&
+ (!Sym.isUndefined() && !Sym.isCommon());
+
+ // We do not support linker redefined symbols (e.g. --wrap) for device
+ // image linking, so the symbols will not be changed after LTO.
+ Res.LinkerRedefined = false;
+ }
+
+ // Add the bitcode file with its resolved symbols to the LTO job.
+ if (Error Err = LTOBackend->add(std::move(*BitcodeFileOrErr), Resolutions))
+ return Err;
+ }
+
+ // Run the LTO job to compile the bitcode.
+ size_t MaxTasks = LTOBackend->getMaxTasks();
+ SmallVector<StringRef> Files(MaxTasks);
+ auto AddStream =
+ [&](size_t Task,
+ const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
+ int FD = -1;
+ auto &TempFile = Files[Task];
+ StringRef Extension = (Triple.isNVPTX() || SaveTemps) ? "s" : "o";
+ std::string TaskStr = Task ? "." + std::to_string(Task) : "";
+ auto TempFileOrErr =
+ createOutputFile(sys::path::filename(ExecutableName) + "." +
+ Triple.getTriple() + "." + Arch + TaskStr,
+ Extension);
+ if (!TempFileOrErr)
+ reportError(TempFileOrErr.takeError());
+ TempFile = *TempFileOrErr;
+ if (std::error_code EC = sys::fs::openFileForWrite(TempFile, FD))
+ reportError(errorCodeToError(EC));
+ return std::make_unique<CachedFileStream>(
+ std::make_unique<llvm::raw_fd_ostream>(FD, true));
+ };
+
+ if (Error Err = LTOBackend->run(AddStream))
+ return Err;
+
+ if (LTOError)
+ return createStringError(inconvertibleErrorCode(),
+ "Errors encountered inside the LTO pipeline.");
+
+ // If we are embedding bitcode we only need the intermediate output.
+ bool SingleOutput = Files.size() == 1;
+ if (Args.hasArg(OPT_embed_bitcode)) {
+ if (BitcodeOutput.size() != 1 || !SingleOutput)
+ return createStringError(inconvertibleErrorCode(),
+ "Cannot embed bitcode with multiple files.");
+ OutputFiles.push_back(Args.MakeArgString(BitcodeOutput.front()));
+ return Error::success();
+ }
+
+ // Append the new inputs to the device linker input.
+ for (StringRef File : Files)
+ OutputFiles.push_back(File);
+
+ return Error::success();
+}
+
+Expected<StringRef> writeOffloadFile(const OffloadFile &File) {
+ const OffloadBinary &Binary = *File.getBinary();
+
+ StringRef Prefix =
+ sys::path::stem(Binary.getMemoryBufferRef().getBufferIdentifier());
+ StringRef Suffix = getImageKindName(Binary.getImageKind());
+
+ auto TempFileOrErr = createOutputFile(
+ Prefix + "-" + Binary.getTriple() + "-" + Binary.getArch(), Suffix);
+ if (!TempFileOrErr)
+ return TempFileOrErr.takeError();
+
+ Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
+ FileOutputBuffer::create(*TempFileOrErr, Binary.getImage().size());
+ if (!OutputOrErr)
+ return OutputOrErr.takeError();
+ std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
+ llvm::copy(Binary.getImage(), Output->getBufferStart());
+ if (Error E = Output->commit())
+ return std::move(E);
+
+ return *TempFileOrErr;
+}
+
+// Compile the module to an object file using the appropriate target machine for
+// the host triple.
+Expected<StringRef> compileModule(Module &M) {
+ llvm::TimeTraceScope TimeScope("Compile module");
+ std::string Msg;
+ const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg);
+ if (!T)
+ return createStringError(inconvertibleErrorCode(), Msg);
+
+ auto Options =
+ codegen::InitTargetOptionsFromCodeGenFlags(Triple(M.getTargetTriple()));
+ StringRef CPU = "";
+ StringRef Features = "";
+ std::unique_ptr<TargetMachine> TM(
+ T->createTargetMachine(M.getTargetTriple(), CPU, Features, Options,
+ Reloc::PIC_, M.getCodeModel()));
+
+ if (M.getDataLayout().isDefault())
+ M.setDataLayout(TM->createDataLayout());
+
+ int FD = -1;
+ auto TempFileOrErr = createOutputFile(
+ sys::path::filename(ExecutableName) + ".image.wrapper", "o");
+ if (!TempFileOrErr)
+ return TempFileOrErr.takeError();
+ if (std::error_code EC = sys::fs::openFileForWrite(*TempFileOrErr, FD))
+ return errorCodeToError(EC);
+
+ auto OS = std::make_unique<llvm::raw_fd_ostream>(FD, true);
+
+ legacy::PassManager CodeGenPasses;
+ TargetLibraryInfoImpl TLII(Triple(M.getTargetTriple()));
+ CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII));
+ if (TM->addPassesToEmitFile(CodeGenPasses, *OS, nullptr, CGFT_ObjectFile))
+ return createStringError(inconvertibleErrorCode(),
+ "Failed to execute host backend");
+ CodeGenPasses.run(M);
+
+ return *TempFileOrErr;
+}
+
+/// Creates the object file containing the device image and runtime
+/// registration code from the device images stored in \p Images.
+Expected<StringRef>
+wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,
+ const ArgList &Args, OffloadKind Kind) {
+ llvm::TimeTraceScope TimeScope("Wrap bundled images");
+
+ SmallVector<ArrayRef<char>, 4> BuffersToWrap;
+ for (const auto &Buffer : Buffers)
+ BuffersToWrap.emplace_back(
+ ArrayRef<char>(Buffer->getBufferStart(), Buffer->getBufferSize()));
+
+ LLVMContext Context;
+ Module M("offload.wrapper.module", Context);
+ M.setTargetTriple(
+ Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
+
+ switch (Kind) {
+ case OFK_OpenMP:
+ if (Error Err = wrapOpenMPBinaries(M, BuffersToWrap))
+ return std::move(Err);
+ break;
+ case OFK_Cuda:
+ if (Error Err = wrapCudaBinary(M, BuffersToWrap.front()))
+ return std::move(Err);
+ break;
+ case OFK_HIP:
+ if (Error Err = wrapHIPBinary(M, BuffersToWrap.front()))
+ return std::move(Err);
+ break;
+ default:
+ return createStringError(inconvertibleErrorCode(),
+ getOffloadKindName(Kind) +
+ " wrapping is not supported");
+ }
+
+ if (Args.hasArg(OPT_print_wrapped_module))
+ errs() << M;
+
+ auto FileOrErr = compileModule(M);
+ if (!FileOrErr)
+ return FileOrErr.takeError();
+ return *FileOrErr;
+}
+
+Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
+bundleOpenMP(ArrayRef<OffloadingImage> Images) {
+ SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
+ for (const OffloadingImage &Image : Images)
+ Buffers.emplace_back(OffloadBinary::write(Image));
+
+ return std::move(Buffers);
+}
+
+Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
+bundleCuda(ArrayRef<OffloadingImage> Images, const ArgList &Args) {
+ SmallVector<std::pair<StringRef, StringRef>, 4> InputFiles;
+ for (const OffloadingImage &Image : Images)
+ InputFiles.emplace_back(std::make_pair(Image.Image->getBufferIdentifier(),
+ Image.StringData.lookup("arch")));
+
+ Triple TheTriple = Triple(Images.front().StringData.lookup("triple"));
+ auto FileOrErr = nvptx::fatbinary(InputFiles, Args);
+ if (!FileOrErr)
+ return FileOrErr.takeError();
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrError =
+ llvm::MemoryBuffer::getFileOrSTDIN(*FileOrErr);
+
+ SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
+ if (std::error_code EC = ImageOrError.getError())
+ return createFileError(*FileOrErr, EC);
+ Buffers.emplace_back(std::move(*ImageOrError));
+
+ return std::move(Buffers);
+}
+
+Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
+bundleHIP(ArrayRef<OffloadingImage> Images, const ArgList &Args) {
+ SmallVector<std::pair<StringRef, StringRef>, 4> InputFiles;
+ for (const OffloadingImage &Image : Images)
+ InputFiles.emplace_back(std::make_pair(Image.Image->getBufferIdentifier(),
+ Image.StringData.lookup("arch")));
+
+ Triple TheTriple = Triple(Images.front().StringData.lookup("triple"));
+ auto FileOrErr = amdgcn::fatbinary(InputFiles, Args);
+ if (!FileOrErr)
+ return FileOrErr.takeError();
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrError =
+ llvm::MemoryBuffer::getFileOrSTDIN(*FileOrErr);
+
+ SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
+ if (std::error_code EC = ImageOrError.getError())
+ return createFileError(*FileOrErr, EC);
+ Buffers.emplace_back(std::move(*ImageOrError));
+
+ return std::move(Buffers);
+}
+
+/// Transforms the input \p Images into the binary format the runtime expects
+/// for the given \p Kind.
+Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
+bundleLinkedOutput(ArrayRef<OffloadingImage> Images, const ArgList &Args,
+ OffloadKind Kind) {
+ llvm::TimeTraceScope TimeScope("Bundle linked output");
+ switch (Kind) {
+ case OFK_OpenMP:
+ return bundleOpenMP(Images);
+ case OFK_Cuda:
+ return bundleCuda(Images, Args);
+ case OFK_HIP:
+ return bundleHIP(Images, Args);
+ default:
+ return createStringError(inconvertibleErrorCode(),
+ getOffloadKindName(Kind) +
+ " bundling is not supported");
+ }
+}
+
+/// Returns a new ArgList containg arguments used for the device linking phase.
+DerivedArgList getLinkerArgs(ArrayRef<OffloadFile> Input,
+ const InputArgList &Args) {
+ DerivedArgList DAL = DerivedArgList(DerivedArgList(Args));
+ for (Arg *A : Args)
+ DAL.append(A);
+
+ // Set the subarchitecture and target triple for this compilation.
+ const OptTable &Tbl = getOptTable();
+ DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_arch_EQ),
+ Args.MakeArgString(Input.front().getBinary()->getArch()));
+ DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_triple_EQ),
+ Args.MakeArgString(Input.front().getBinary()->getTriple()));
+
+ // If every input file is bitcode we have whole program visibility as we do
+ // only support static linking with bitcode.
+ auto ContainsBitcode = [](const OffloadFile &F) {
+ return identify_magic(F.getBinary()->getImage()) == file_magic::bitcode;
+ };
+ if (llvm::all_of(Input, ContainsBitcode))
+ DAL.AddFlagArg(nullptr, Tbl.getOption(OPT_whole_program));
+
+ // Forward '-Xoffload-linker' options to the appropriate backend.
+ for (StringRef Arg : Args.getAllArgValues(OPT_device_linker_args_EQ)) {
+ auto [Triple, Value] = Arg.split('=');
+ if (Value.empty())
+ DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_linker_arg_EQ),
+ Args.MakeArgString(Triple));
+ else if (Triple == DAL.getLastArgValue(OPT_triple_EQ))
+ DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_linker_arg_EQ),
+ Args.MakeArgString(Value));
+ }
+
+ return DAL;
+}
+
+/// Transforms all the extracted offloading input files into an image that can
+/// be registered by the runtime.
+Expected<SmallVector<StringRef>>
+linkAndWrapDeviceFiles(SmallVectorImpl<OffloadFile> &LinkerInputFiles,
+ const InputArgList &Args, char **Argv, int Argc) {
+ llvm::TimeTraceScope TimeScope("Handle all device input");
+
+ DenseMap<OffloadFile::TargetID, SmallVector<OffloadFile>> InputMap;
+ for (auto &File : LinkerInputFiles)
+ InputMap[File].emplace_back(std::move(File));
+ LinkerInputFiles.clear();
+
+ SmallVector<SmallVector<OffloadFile>> InputsForTarget;
+ for (auto &[ID, Input] : InputMap)
+ InputsForTarget.emplace_back(std::move(Input));
+ InputMap.clear();
+
+ std::mutex ImageMtx;
+ DenseMap<OffloadKind, SmallVector<OffloadingImage>> Images;
+ auto Err = parallelForEachError(InputsForTarget, [&](auto &Input) -> Error {
+ llvm::TimeTraceScope TimeScope("Link device input");
+
+ // Each thread needs its own copy of the base arguments to maintain
+ // per-device argument storage of synthetic strings.
+ const OptTable &Tbl = getOptTable();
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+ auto BaseArgs =
+ Tbl.parseArgs(Argc, Argv, OPT_INVALID, Saver, [](StringRef Err) {
+ reportError(createStringError(inconvertibleErrorCode(), Err));
+ });
+ auto LinkerArgs = getLinkerArgs(Input, BaseArgs);
+
+ DenseSet<OffloadKind> ActiveOffloadKinds;
+ for (const auto &File : Input)
+ if (File.getBinary()->getOffloadKind() != OFK_None)
+ ActiveOffloadKinds.insert(File.getBinary()->getOffloadKind());
+
+ // First link and remove all the input files containing bitcode.
+ SmallVector<StringRef> InputFiles;
+ if (Error Err = linkBitcodeFiles(Input, InputFiles, LinkerArgs))
+ return Err;
+
+ // Write any remaining device inputs to an output file for the linker.
+ for (const OffloadFile &File : Input) {
+ auto FileNameOrErr = writeOffloadFile(File);
+ if (!FileNameOrErr)
+ return FileNameOrErr.takeError();
+ InputFiles.emplace_back(*FileNameOrErr);
+ }
+
+ // Link the remaining device files using the device linker.
+ auto OutputOrErr = !Args.hasArg(OPT_embed_bitcode)
+ ? linkDevice(InputFiles, LinkerArgs)
+ : InputFiles.front();
+ if (!OutputOrErr)
+ return OutputOrErr.takeError();
+
+ // Store the offloading image for each linked output file.
+ for (OffloadKind Kind : ActiveOffloadKinds) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
+ llvm::MemoryBuffer::getFileOrSTDIN(*OutputOrErr);
+ if (std::error_code EC = FileOrErr.getError()) {
+ if (DryRun)
+ FileOrErr = MemoryBuffer::getMemBuffer("");
+ else
+ return createFileError(*OutputOrErr, EC);
+ }
+
+ std::scoped_lock<decltype(ImageMtx)> Guard(ImageMtx);
+ OffloadingImage TheImage{};
+ TheImage.TheImageKind =
+ Args.hasArg(OPT_embed_bitcode) ? IMG_Bitcode : IMG_Object;
+ TheImage.TheOffloadKind = Kind;
+ TheImage.StringData = {
+ {"triple",
+ Args.MakeArgString(LinkerArgs.getLastArgValue(OPT_triple_EQ))},
+ {"arch",
+ Args.MakeArgString(LinkerArgs.getLastArgValue(OPT_arch_EQ))}};
+ TheImage.Image = std::move(*FileOrErr);
+
+ Images[Kind].emplace_back(std::move(TheImage));
+ }
+ return Error::success();
+ });
+ if (Err)
+ return std::move(Err);
+
+ // Create a binary image of each offloading image and embed it into a new
+ // object file.
+ SmallVector<StringRef> WrappedOutput;
+ for (auto &[Kind, Input] : Images) {
+ // We sort the entries before bundling so they appear in a deterministic
+ // order in the final binary.
+ llvm::sort(Input, [](OffloadingImage &A, OffloadingImage &B) {
+ return A.StringData["triple"] > B.StringData["triple"] ||
+ A.StringData["arch"] > B.StringData["arch"] ||
+ A.TheOffloadKind < B.TheOffloadKind;
+ });
+ auto BundledImagesOrErr = bundleLinkedOutput(Input, Args, Kind);
+ if (!BundledImagesOrErr)
+ return BundledImagesOrErr.takeError();
+ auto OutputOrErr = wrapDeviceImages(*BundledImagesOrErr, Args, Kind);
+ if (!OutputOrErr)
+ return OutputOrErr.takeError();
+ WrappedOutput.push_back(*OutputOrErr);
+ }
+
+ return WrappedOutput;
+}
+
+std::optional<std::string> findFile(StringRef Dir, StringRef Root,
+ const Twine &Name) {
+ SmallString<128> Path;
+ if (Dir.startswith("="))
+ sys::path::append(Path, Root, Dir.substr(1), Name);
+ else
+ sys::path::append(Path, Dir, Name);
+
+ if (sys::fs::exists(Path))
+ return static_cast<std::string>(Path);
+ return std::nullopt;
+}
+
+std::optional<std::string>
+findFromSearchPaths(StringRef Name, StringRef Root,
+ ArrayRef<StringRef> SearchPaths) {
+ for (StringRef Dir : SearchPaths)
+ if (std::optional<std::string> File = findFile(Dir, Root, Name))
+ return File;
+ return std::nullopt;
+}
+
+std::optional<std::string>
+searchLibraryBaseName(StringRef Name, StringRef Root,
+ ArrayRef<StringRef> SearchPaths) {
+ for (StringRef Dir : SearchPaths) {
+ if (std::optional<std::string> File =
+ findFile(Dir, Root, "lib" + Name + ".so"))
+ return File;
+ if (std::optional<std::string> File =
+ findFile(Dir, Root, "lib" + Name + ".a"))
+ return File;
+ }
+ return std::nullopt;
+}
+
+/// Search for static libraries in the linker's library path given input like
+/// `-lfoo` or `-l:libfoo.a`.
+std::optional<std::string> searchLibrary(StringRef Input, StringRef Root,
+ ArrayRef<StringRef> SearchPaths) {
+ if (Input.startswith(":"))
+ return findFromSearchPaths(Input.drop_front(), Root, SearchPaths);
+ return searchLibraryBaseName(Input, Root, SearchPaths);
+}
+
+/// Common redeclaration of needed symbol flags.
+enum Symbol : uint32_t {
+ Sym_None = 0,
+ Sym_Undefined = 1U << 1,
+ Sym_Weak = 1U << 2,
+};
+
+/// Scan the symbols from a BitcodeFile \p Buffer and record if we need to
+/// extract any symbols from it.
+Expected<bool> getSymbolsFromBitcode(MemoryBufferRef Buffer, StringSaver &Saver,
+ DenseMap<StringRef, Symbol> &Syms) {
+ Expected<IRSymtabFile> IRSymtabOrErr = readIRSymtab(Buffer);
+ if (!IRSymtabOrErr)
+ return IRSymtabOrErr.takeError();
+
+ bool ShouldExtract = false;
+ for (unsigned I = 0; I != IRSymtabOrErr->Mods.size(); ++I) {
+ for (const auto &Sym : IRSymtabOrErr->TheReader.module_symbols(I)) {
+ if (Sym.isFormatSpecific() || !Sym.isGlobal())
+ continue;
+
+ bool NewSymbol = Syms.count(Sym.getName()) == 0;
+ auto &OldSym = Syms[Saver.save(Sym.getName())];
+
+ // We will extract if it defines a currenlty undefined non-weak symbol.
+ bool ResolvesStrongReference =
+ ((OldSym & Sym_Undefined && !(OldSym & Sym_Weak)) &&
+ !Sym.isUndefined());
+ // We will extract if it defines a new global symbol visible to the host.
+ bool NewGlobalSymbol =
+ ((NewSymbol || (OldSym & Sym_Undefined)) && !Sym.isUndefined() &&
+ !Sym.canBeOmittedFromSymbolTable() &&
+ (Sym.getVisibility() != GlobalValue::HiddenVisibility));
+ ShouldExtract |= ResolvesStrongReference | NewGlobalSymbol;
+
+ // Update this symbol in the "table" with the new information.
+ if (OldSym & Sym_Undefined && !Sym.isUndefined())
+ OldSym = static_cast<Symbol>(OldSym & ~Sym_Undefined);
+ if (Sym.isUndefined() && NewSymbol)
+ OldSym = static_cast<Symbol>(OldSym | Sym_Undefined);
+ if (Sym.isWeak())
+ OldSym = static_cast<Symbol>(OldSym | Sym_Weak);
+ }
+ }
+
+ return ShouldExtract;
+}
+
+/// Scan the symbols from an ObjectFile \p Obj and record if we need to extract
+/// any symbols from it.
+Expected<bool> getSymbolsFromObject(const ObjectFile &Obj, StringSaver &Saver,
+ DenseMap<StringRef, Symbol> &Syms) {
+ bool ShouldExtract = false;
+ for (SymbolRef Sym : Obj.symbols()) {
+ auto FlagsOrErr = Sym.getFlags();
+ if (!FlagsOrErr)
+ return FlagsOrErr.takeError();
+
+ if (!(*FlagsOrErr & SymbolRef::SF_Global) ||
+ (*FlagsOrErr & SymbolRef::SF_FormatSpecific))
+ continue;
+
+ auto NameOrErr = Sym.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+
+ bool NewSymbol = Syms.count(*NameOrErr) == 0;
+ auto &OldSym = Syms[Saver.save(*NameOrErr)];
+
+ // We will extract if it defines a currenlty undefined non-weak symbol.
+ bool ResolvesStrongReference = (OldSym & Sym_Undefined) &&
+ !(OldSym & Sym_Weak) &&
+ !(*FlagsOrErr & SymbolRef::SF_Undefined);
+
+ // We will extract if it defines a new global symbol visible to the host.
+ bool NewGlobalSymbol = ((NewSymbol || (OldSym & Sym_Undefined)) &&
+ !(*FlagsOrErr & SymbolRef::SF_Undefined) &&
+ !(*FlagsOrErr & SymbolRef::SF_Hidden));
+ ShouldExtract |= ResolvesStrongReference | NewGlobalSymbol;
+
+ // Update this symbol in the "table" with the new information.
+ if (OldSym & Sym_Undefined && !(*FlagsOrErr & SymbolRef::SF_Undefined))
+ OldSym = static_cast<Symbol>(OldSym & ~Sym_Undefined);
+ if (*FlagsOrErr & SymbolRef::SF_Undefined && NewSymbol)
+ OldSym = static_cast<Symbol>(OldSym | Sym_Undefined);
+ if (*FlagsOrErr & SymbolRef::SF_Weak)
+ OldSym = static_cast<Symbol>(OldSym | Sym_Weak);
+ }
+ return ShouldExtract;
+}
+
+/// Attempt to 'resolve' symbols found in input files. We use this to
+/// determine if an archive member needs to be extracted. An archive member
+/// will be extracted if any of the following is true.
+/// 1) It defines an undefined symbol in a regular object filie.
+/// 2) It defines a global symbol without hidden visibility that has not
+/// yet been defined.
+Expected<bool> getSymbols(StringRef Image, StringSaver &Saver,
+ DenseMap<StringRef, Symbol> &Syms) {
+ MemoryBufferRef Buffer = MemoryBufferRef(Image, "");
+ switch (identify_magic(Image)) {
+ case file_magic::bitcode:
+ return getSymbolsFromBitcode(Buffer, Saver, Syms);
+ case file_magic::elf_relocatable: {
+ Expected<std::unique_ptr<ObjectFile>> ObjFile =
+ ObjectFile::createObjectFile(Buffer);
+ if (!ObjFile)
+ return ObjFile.takeError();
+ return getSymbolsFromObject(**ObjFile, Saver, Syms);
+ }
+ default:
+ return false;
+ }
+}
+
+/// Search the input files and libraries for embedded device offloading code
+/// and add it to the list of files to be linked. Files coming from static
+/// libraries are only added to the input if they are used by an existing
+/// input file.
+Expected<SmallVector<OffloadFile>> getDeviceInput(const ArgList &Args) {
+ llvm::TimeTraceScope TimeScope("ExtractDeviceCode");
+
+ StringRef Root = Args.getLastArgValue(OPT_sysroot_EQ);
+ SmallVector<StringRef> LibraryPaths;
+ for (const opt::Arg *Arg : Args.filtered(OPT_library_path))
+ LibraryPaths.push_back(Arg->getValue());
+
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+
+ // Try to extract device code from the linker input files.
+ SmallVector<OffloadFile> InputFiles;
+ DenseMap<OffloadFile::TargetID, DenseMap<StringRef, Symbol>> Syms;
+ for (const opt::Arg *Arg : Args.filtered(OPT_INPUT, OPT_library)) {
+ std::optional<std::string> Filename =
+ Arg->getOption().matches(OPT_library)
+ ? searchLibrary(Arg->getValue(), Root, LibraryPaths)
+ : std::string(Arg->getValue());
+
+ if (!Filename && Arg->getOption().matches(OPT_library))
+ reportError(createStringError(inconvertibleErrorCode(),
+ "unable to find library -l%s",
+ Arg->getValue()));
+
+ if (!Filename || !sys::fs::exists(*Filename) ||
+ sys::fs::is_directory(*Filename))
+ continue;
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+ MemoryBuffer::getFileOrSTDIN(*Filename);
+ if (std::error_code EC = BufferOrErr.getError())
+ return createFileError(*Filename, EC);
+
+ MemoryBufferRef Buffer = **BufferOrErr;
+ if (identify_magic(Buffer.getBuffer()) == file_magic::elf_shared_object)
+ continue;
+
+ SmallVector<OffloadFile> Binaries;
+ if (Error Err = extractOffloadBinaries(Buffer, Binaries))
+ return std::move(Err);
+
+ // We only extract archive members that are needed.
+ bool IsArchive = identify_magic(Buffer.getBuffer()) == file_magic::archive;
+ bool Extracted = true;
+ while (Extracted) {
+ Extracted = false;
+ for (OffloadFile &Binary : Binaries) {
+ if (!Binary.getBinary())
+ continue;
+
+ // If we don't have an object file for this architecture do not
+ // extract.
+ if (IsArchive && !Syms.count(Binary))
+ continue;
+
+ Expected<bool> ExtractOrErr =
+ getSymbols(Binary.getBinary()->getImage(), Saver, Syms[Binary]);
+ if (!ExtractOrErr)
+ return ExtractOrErr.takeError();
+
+ Extracted = IsArchive && *ExtractOrErr;
+
+ if (!IsArchive || Extracted)
+ InputFiles.emplace_back(std::move(Binary));
+
+ // If we extracted any files we need to check all the symbols again.
+ if (Extracted)
+ break;
+ }
+ }
+ }
+
+ for (StringRef Library : Args.getAllArgValues(OPT_bitcode_library_EQ)) {
+ auto FileOrErr = getInputBitcodeLibrary(Library);
+ if (!FileOrErr)
+ return FileOrErr.takeError();
+ InputFiles.push_back(std::move(*FileOrErr));
+ }
+
+ return std::move(InputFiles);
+}
+
+} // namespace
+
+int main(int Argc, char **Argv) {
+ InitLLVM X(Argc, Argv);
+ InitializeAllTargetInfos();
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmParsers();
+ InitializeAllAsmPrinters();
+
+ LinkerExecutable = Argv[0];
+ sys::PrintStackTraceOnErrorSignal(Argv[0]);
+
+ const OptTable &Tbl = getOptTable();
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+ auto Args = Tbl.parseArgs(Argc, Argv, OPT_INVALID, Saver, [&](StringRef Err) {
+ reportError(createStringError(inconvertibleErrorCode(), Err));
+ });
+
+ if (Args.hasArg(OPT_help) || Args.hasArg(OPT_help_hidden)) {
+ Tbl.printHelp(
+ outs(),
+ "clang-linker-wrapper [options] -- <options to passed to the linker>",
+ "\nA wrapper utility over the host linker. It scans the input files\n"
+ "for sections that require additional processing prior to linking.\n"
+ "The will then transparently pass all arguments and input to the\n"
+ "specified host linker to create the final binary.\n",
+ Args.hasArg(OPT_help_hidden), Args.hasArg(OPT_help_hidden));
+ return EXIT_SUCCESS;
+ }
+ if (Args.hasArg(OPT_v)) {
+ printVersion(outs());
+ return EXIT_SUCCESS;
+ }
+
+ // This forwards '-mllvm' arguments to LLVM if present.
+ SmallVector<const char *> NewArgv = {Argv[0]};
+ for (const opt::Arg *Arg : Args.filtered(OPT_mllvm))
+ NewArgv.push_back(Arg->getValue());
+ for (const opt::Arg *Arg : Args.filtered(OPT_offload_opt_eq_minus))
+ NewArgv.push_back(Args.MakeArgString(StringRef("-") + Arg->getValue()));
+ cl::ParseCommandLineOptions(NewArgv.size(), &NewArgv[0]);
+
+ Verbose = Args.hasArg(OPT_verbose);
+ DryRun = Args.hasArg(OPT_dry_run);
+ SaveTemps = Args.hasArg(OPT_save_temps);
+ ExecutableName = Args.getLastArgValue(OPT_o, "a.out");
+ CudaBinaryPath = Args.getLastArgValue(OPT_cuda_path_EQ).str();
+
+ parallel::strategy = hardware_concurrency(1);
+ if (auto *Arg = Args.getLastArg(OPT_wrapper_jobs)) {
+ unsigned Threads = 0;
+ if (!llvm::to_integer(Arg->getValue(), Threads) || Threads == 0)
+ reportError(createStringError(
+ inconvertibleErrorCode(), "%s: expected a positive integer, got '%s'",
+ Arg->getSpelling().data(), Arg->getValue()));
+ parallel::strategy = hardware_concurrency(Threads);
+ }
+
+ if (Args.hasArg(OPT_wrapper_time_trace_eq)) {
+ unsigned Granularity;
+ Args.getLastArgValue(OPT_wrapper_time_trace_granularity, "500")
+ .getAsInteger(10, Granularity);
+ timeTraceProfilerInitialize(Granularity, Argv[0]);
+ }
+
+ {
+ llvm::TimeTraceScope TimeScope("Execute linker wrapper");
+
+ // Extract the device input files stored in the host fat binary.
+ auto DeviceInputFiles = getDeviceInput(Args);
+ if (!DeviceInputFiles)
+ reportError(DeviceInputFiles.takeError());
+
+ // Link and wrap the device images extracted from the linker input.
+ auto FilesOrErr =
+ linkAndWrapDeviceFiles(*DeviceInputFiles, Args, Argv, Argc);
+ if (!FilesOrErr)
+ reportError(FilesOrErr.takeError());
+
+ // Run the host linking job with the rendered arguments.
+ if (Error Err = runLinker(*FilesOrErr, Args))
+ reportError(std::move(Err));
+ }
+
+ if (const opt::Arg *Arg = Args.getLastArg(OPT_wrapper_time_trace_eq)) {
+ if (Error Err = timeTraceProfilerWrite(Arg->getValue(), ExecutableName))
+ reportError(std::move(Err));
+ timeTraceProfilerCleanup();
+ }
+
+ // Remove the temporary files created.
+ if (!SaveTemps)
+ for (const auto &TempFile : TempFiles)
+ if (std::error_code EC = sys::fs::remove(TempFile))
+ reportError(createFileError(TempFile, EC));
+
+ return EXIT_SUCCESS;
+}
diff --git a/gnu/llvm/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td b/gnu/llvm/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
new file mode 100644
index 00000000000..c12aac77c3b
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
@@ -0,0 +1,124 @@
+include "llvm/Option/OptParser.td"
+
+def WrapperOnlyOption : OptionFlag;
+def DeviceOnlyOption : OptionFlag;
+
+def help : Flag<["--"], "help">,
+ HelpText<"Display available options (--help-hidden for more)">;
+
+def help_hidden : Flag<["--"], "help-hidden">,
+ HelpText<"Display all available options">;
+
+// Flags for the linker wrapper.
+def linker_path_EQ : Joined<["--"], "linker-path=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<path>">,
+ HelpText<"The linker executable to invoke">;
+def cuda_path_EQ : Joined<["--"], "cuda-path=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<dir>">,
+ HelpText<"Set the system CUDA path">;
+def host_triple_EQ : Joined<["--"], "host-triple=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<triple>">,
+ HelpText<"Triple to use for the host compilation">;
+def opt_level : Joined<["--"], "opt-level=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<O0, O1, O2, or O3>">,
+ HelpText<"Optimization level for LTO">;
+def bitcode_library_EQ : Joined<["--"], "bitcode-library=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<kind>-<triple>-<arch>=<path>">,
+ HelpText<"Extra bitcode library to link">;
+def device_linker_args_EQ : Joined<["--"], "device-linker=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<value> or <triple>=<value>">,
+ HelpText<"Arguments to pass to the device linker invocation">;
+def dry_run : Flag<["--"], "dry-run">,
+ Flags<[WrapperOnlyOption]>,
+ HelpText<"Print program arguments without running">;
+def verbose : Flag<["--"], "wrapper-verbose">,
+ Flags<[WrapperOnlyOption]>, HelpText<"Verbose output from tools">;
+def embed_bitcode : Flag<["--"], "embed-bitcode">,
+ Flags<[WrapperOnlyOption]>, HelpText<"Embed linked bitcode in the module">;
+def debug : Flag<["--"], "device-debug">, Flags<[WrapperOnlyOption]>,
+ HelpText<"Use debugging">;
+def ptxas_arg : Joined<["--"], "ptxas-arg=">,
+ Flags<[WrapperOnlyOption]>,
+ HelpText<"Argument to pass to the 'ptxas' invocation">;
+def pass_remarks_EQ : Joined<["--"], "pass-remarks=">,
+ Flags<[WrapperOnlyOption]>, HelpText<"Pass remarks for LTO">;
+def pass_remarks_missed_EQ : Joined<["--"], "pass-remarks-missed=">,
+ Flags<[WrapperOnlyOption]>, HelpText<"Pass remarks for LTO">;
+def pass_remarks_analysis_EQ : Joined<["--"], "pass-remarks-analysis=">,
+ Flags<[WrapperOnlyOption]>, HelpText<"Pass remarks for LTO">;
+def print_wrapped_module : Flag<["--"], "print-wrapped-module">,
+ Flags<[WrapperOnlyOption]>,
+ HelpText<"Print the wrapped module's IR for testing">;
+def save_temps : Flag<["--"], "save-temps">,
+ Flags<[WrapperOnlyOption]>, HelpText<"Save intermediate results">;
+
+def wrapper_time_trace_eq : Joined<["--"], "wrapper-time-trace=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<file>">,
+ HelpText<"Enable time-trace and write the output to <file>">;
+def wrapper_time_trace_granularity : Joined<["--"], "wrapper-time-trace-granularity=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<number>">,
+ HelpText<"Set the granularity of time-trace updates">;
+
+def wrapper_jobs : Joined<["--"], "wrapper-jobs=">,
+ Flags<[WrapperOnlyOption]>, MetaVarName<"<number>">,
+ HelpText<"Sets the number of parallel jobs to use for device linking">;
+
+// Flags passed to the device linker.
+def arch_EQ : Joined<["--"], "arch=">,
+ Flags<[DeviceOnlyOption, HelpHidden]>, MetaVarName<"<arch>">,
+ HelpText<"The device subarchitecture">;
+def triple_EQ : Joined<["--"], "triple=">,
+ Flags<[DeviceOnlyOption, HelpHidden]>, MetaVarName<"<triple>">,
+ HelpText<"The device target triple">;
+def whole_program : Flag<["--"], "whole-program">,
+ Flags<[DeviceOnlyOption, HelpHidden]>,
+ HelpText<"LTO has visibility of all input files">;
+def linker_arg_EQ : Joined<["--"], "linker-arg=">,
+ Flags<[DeviceOnlyOption, HelpHidden]>,
+ HelpText<"An extra argument to be passed to the linker">;
+
+// Separator between the linker wrapper and host linker flags.
+def separator : Flag<["--"], "">, Flags<[WrapperOnlyOption]>,
+ HelpText<"The separator for the wrapped linker arguments">;
+
+// Arguments for the LLVM backend.
+def mllvm : Separate<["-"], "mllvm">, Flags<[WrapperOnlyOption]>,
+ MetaVarName<"<arg>">, HelpText<"Arguments passed to the LLVM invocation">;
+def offload_opt_eq_minus : Joined<["--", "-"], "offload-opt=-">, Flags<[HelpHidden, WrapperOnlyOption]>,
+ HelpText<"Options passed to LLVM">;
+
+// Standard linker flags also used by the linker wrapper.
+def sysroot_EQ : Joined<["--"], "sysroot">, HelpText<"Set the system root">;
+
+def o : JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
+ HelpText<"Path to file to write output">;
+def output_EQ : Joined<["--"], "output=">, Alias<o>, Flags<[HelpHidden]>,
+ HelpText<"Alias for -o">;
+def output : Separate<["--"], "output">, Alias<o>, Flags<[HelpHidden]>,
+ HelpText<"Alias for -o">;
+
+def library_path : JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
+ HelpText<"Add <dir> to the library search path">;
+def library_path_S : Separate<["--", "-"], "library-path">, Flags<[HelpHidden]>,
+ Alias<library_path>;
+def library_path_EQ : Joined<["--", "-"], "library-path=">, Flags<[HelpHidden]>,
+ Alias<library_path>;
+
+def library : JoinedOrSeparate<["-"], "l">, MetaVarName<"<libname>">,
+ HelpText<"Search for library <libname>">;
+def library_S : Separate<["--", "-"], "library">, Flags<[HelpHidden]>,
+ Alias<library_path>;
+def library_EQ : Joined<["--", "-"], "library=">, Flags<[HelpHidden]>,
+ Alias<library_path>;
+
+def as_needed : Flag<["--", "-"], "as-needed">;
+def no_as_needed : Flag<["--", "-"], "no-as-needed">;
+
+def rpath : Separate<["--", "-"], "rpath">;
+def rpath_EQ : Joined<["--", "-"], "rpath=">, Flags<[HelpHidden]>, Alias<rpath>;
+
+def dynamic_linker : Separate<["--", "-"], "dynamic-linker">;
+def dynamic_linker_EQ : Joined<["--", "-"], "dynamic-linker=">, Alias<dynamic_linker>;
+
+def v : Flag<["--", "-"], "v">, HelpText<"Display the version number and exit">;
+def version : Flag<["--", "-"], "version">, Flags<[HelpHidden]>, Alias<v>;
diff --git a/gnu/llvm/clang/tools/clang-linker-wrapper/OffloadWrapper.cpp b/gnu/llvm/clang/tools/clang-linker-wrapper/OffloadWrapper.cpp
new file mode 100644
index 00000000000..dbfd896362c
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-linker-wrapper/OffloadWrapper.cpp
@@ -0,0 +1,622 @@
+//===- OffloadWrapper.cpp ---------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "OffloadWrapper.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Object/OffloadBinary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+using namespace llvm;
+
+namespace {
+/// Magic number that begins the section containing the CUDA fatbinary.
+constexpr unsigned CudaFatMagic = 0x466243b1;
+constexpr unsigned HIPFatMagic = 0x48495046;
+
+/// Copied from clang/CGCudaRuntime.h.
+enum OffloadEntryKindFlag : uint32_t {
+ /// Mark the entry as a global entry. This indicates the presense of a
+ /// kernel if the size size field is zero and a variable otherwise.
+ OffloadGlobalEntry = 0x0,
+ /// Mark the entry as a managed global variable.
+ OffloadGlobalManagedEntry = 0x1,
+ /// Mark the entry as a surface variable.
+ OffloadGlobalSurfaceEntry = 0x2,
+ /// Mark the entry as a texture variable.
+ OffloadGlobalTextureEntry = 0x3,
+};
+
+IntegerType *getSizeTTy(Module &M) {
+ LLVMContext &C = M.getContext();
+ switch (M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))) {
+ case 4u:
+ return Type::getInt32Ty(C);
+ case 8u:
+ return Type::getInt64Ty(C);
+ }
+ llvm_unreachable("unsupported pointer type size");
+}
+
+// struct __tgt_offload_entry {
+// void *addr;
+// char *name;
+// size_t size;
+// int32_t flags;
+// int32_t reserved;
+// };
+StructType *getEntryTy(Module &M) {
+ LLVMContext &C = M.getContext();
+ StructType *EntryTy = StructType::getTypeByName(C, "__tgt_offload_entry");
+ if (!EntryTy)
+ EntryTy = StructType::create("__tgt_offload_entry", Type::getInt8PtrTy(C),
+ Type::getInt8PtrTy(C), getSizeTTy(M),
+ Type::getInt32Ty(C), Type::getInt32Ty(C));
+ return EntryTy;
+}
+
+PointerType *getEntryPtrTy(Module &M) {
+ return PointerType::getUnqual(getEntryTy(M));
+}
+
+// struct __tgt_device_image {
+// void *ImageStart;
+// void *ImageEnd;
+// __tgt_offload_entry *EntriesBegin;
+// __tgt_offload_entry *EntriesEnd;
+// };
+StructType *getDeviceImageTy(Module &M) {
+ LLVMContext &C = M.getContext();
+ StructType *ImageTy = StructType::getTypeByName(C, "__tgt_device_image");
+ if (!ImageTy)
+ ImageTy = StructType::create("__tgt_device_image", Type::getInt8PtrTy(C),
+ Type::getInt8PtrTy(C), getEntryPtrTy(M),
+ getEntryPtrTy(M));
+ return ImageTy;
+}
+
+PointerType *getDeviceImagePtrTy(Module &M) {
+ return PointerType::getUnqual(getDeviceImageTy(M));
+}
+
+// struct __tgt_bin_desc {
+// int32_t NumDeviceImages;
+// __tgt_device_image *DeviceImages;
+// __tgt_offload_entry *HostEntriesBegin;
+// __tgt_offload_entry *HostEntriesEnd;
+// };
+StructType *getBinDescTy(Module &M) {
+ LLVMContext &C = M.getContext();
+ StructType *DescTy = StructType::getTypeByName(C, "__tgt_bin_desc");
+ if (!DescTy)
+ DescTy = StructType::create("__tgt_bin_desc", Type::getInt32Ty(C),
+ getDeviceImagePtrTy(M), getEntryPtrTy(M),
+ getEntryPtrTy(M));
+ return DescTy;
+}
+
+PointerType *getBinDescPtrTy(Module &M) {
+ return PointerType::getUnqual(getBinDescTy(M));
+}
+
+/// Creates binary descriptor for the given device images. Binary descriptor
+/// is an object that is passed to the offloading runtime at program startup
+/// and it describes all device images available in the executable or shared
+/// library. It is defined as follows
+///
+/// __attribute__((visibility("hidden")))
+/// extern __tgt_offload_entry *__start_omp_offloading_entries;
+/// __attribute__((visibility("hidden")))
+/// extern __tgt_offload_entry *__stop_omp_offloading_entries;
+///
+/// static const char Image0[] = { <Bufs.front() contents> };
+/// ...
+/// static const char ImageN[] = { <Bufs.back() contents> };
+///
+/// static const __tgt_device_image Images[] = {
+/// {
+/// Image0, /*ImageStart*/
+/// Image0 + sizeof(Image0), /*ImageEnd*/
+/// __start_omp_offloading_entries, /*EntriesBegin*/
+/// __stop_omp_offloading_entries /*EntriesEnd*/
+/// },
+/// ...
+/// {
+/// ImageN, /*ImageStart*/
+/// ImageN + sizeof(ImageN), /*ImageEnd*/
+/// __start_omp_offloading_entries, /*EntriesBegin*/
+/// __stop_omp_offloading_entries /*EntriesEnd*/
+/// }
+/// };
+///
+/// static const __tgt_bin_desc BinDesc = {
+/// sizeof(Images) / sizeof(Images[0]), /*NumDeviceImages*/
+/// Images, /*DeviceImages*/
+/// __start_omp_offloading_entries, /*HostEntriesBegin*/
+/// __stop_omp_offloading_entries /*HostEntriesEnd*/
+/// };
+///
+/// Global variable that represents BinDesc is returned.
+GlobalVariable *createBinDesc(Module &M, ArrayRef<ArrayRef<char>> Bufs) {
+ LLVMContext &C = M.getContext();
+ // Create external begin/end symbols for the offload entries table.
+ auto *EntriesB = new GlobalVariable(
+ M, getEntryTy(M), /*isConstant*/ true, GlobalValue::ExternalLinkage,
+ /*Initializer*/ nullptr, "__start_omp_offloading_entries");
+ EntriesB->setVisibility(GlobalValue::HiddenVisibility);
+ auto *EntriesE = new GlobalVariable(
+ M, getEntryTy(M), /*isConstant*/ true, GlobalValue::ExternalLinkage,
+ /*Initializer*/ nullptr, "__stop_omp_offloading_entries");
+ EntriesE->setVisibility(GlobalValue::HiddenVisibility);
+
+ // We assume that external begin/end symbols that we have created above will
+ // be defined by the linker. But linker will do that only if linker inputs
+ // have section with "omp_offloading_entries" name which is not guaranteed.
+ // So, we just create dummy zero sized object in the offload entries section
+ // to force linker to define those symbols.
+ auto *DummyInit =
+ ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u));
+ auto *DummyEntry = new GlobalVariable(
+ M, DummyInit->getType(), true, GlobalVariable::ExternalLinkage, DummyInit,
+ "__dummy.omp_offloading.entry");
+ DummyEntry->setSection("omp_offloading_entries");
+ DummyEntry->setVisibility(GlobalValue::HiddenVisibility);
+
+ auto *Zero = ConstantInt::get(getSizeTTy(M), 0u);
+ Constant *ZeroZero[] = {Zero, Zero};
+
+ // Create initializer for the images array.
+ SmallVector<Constant *, 4u> ImagesInits;
+ ImagesInits.reserve(Bufs.size());
+ for (ArrayRef<char> Buf : Bufs) {
+ auto *Data = ConstantDataArray::get(C, Buf);
+ auto *Image = new GlobalVariable(M, Data->getType(), /*isConstant*/ true,
+ GlobalVariable::InternalLinkage, Data,
+ ".omp_offloading.device_image");
+ Image->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+ Image->setSection(".llvm.offloading");
+ Image->setAlignment(Align(object::OffloadBinary::getAlignment()));
+
+ auto *Size = ConstantInt::get(getSizeTTy(M), Buf.size());
+ Constant *ZeroSize[] = {Zero, Size};
+
+ auto *ImageB =
+ ConstantExpr::getGetElementPtr(Image->getValueType(), Image, ZeroZero);
+ auto *ImageE =
+ ConstantExpr::getGetElementPtr(Image->getValueType(), Image, ZeroSize);
+
+ ImagesInits.push_back(ConstantStruct::get(getDeviceImageTy(M), ImageB,
+ ImageE, EntriesB, EntriesE));
+ }
+
+ // Then create images array.
+ auto *ImagesData = ConstantArray::get(
+ ArrayType::get(getDeviceImageTy(M), ImagesInits.size()), ImagesInits);
+
+ auto *Images =
+ new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true,
+ GlobalValue::InternalLinkage, ImagesData,
+ ".omp_offloading.device_images");
+ Images->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+
+ auto *ImagesB =
+ ConstantExpr::getGetElementPtr(Images->getValueType(), Images, ZeroZero);
+
+ // And finally create the binary descriptor object.
+ auto *DescInit = ConstantStruct::get(
+ getBinDescTy(M),
+ ConstantInt::get(Type::getInt32Ty(C), ImagesInits.size()), ImagesB,
+ EntriesB, EntriesE);
+
+ return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true,
+ GlobalValue::InternalLinkage, DescInit,
+ ".omp_offloading.descriptor");
+}
+
+void createRegisterFunction(Module &M, GlobalVariable *BinDesc) {
+ LLVMContext &C = M.getContext();
+ auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
+ auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
+ ".omp_offloading.descriptor_reg", &M);
+ Func->setSection(".text.startup");
+
+ // Get __tgt_register_lib function declaration.
+ auto *RegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(M),
+ /*isVarArg*/ false);
+ FunctionCallee RegFuncC =
+ M.getOrInsertFunction("__tgt_register_lib", RegFuncTy);
+
+ // Construct function body
+ IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
+ Builder.CreateCall(RegFuncC, BinDesc);
+ Builder.CreateRetVoid();
+
+ // Add this function to constructors.
+ // Set priority to 1 so that __tgt_register_lib is executed AFTER
+ // __tgt_register_requires (we want to know what requirements have been
+ // asked for before we load a libomptarget plugin so that by the time the
+ // plugin is loaded it can report how many devices there are which can
+ // satisfy these requirements).
+ appendToGlobalCtors(M, Func, /*Priority*/ 1);
+}
+
+void createUnregisterFunction(Module &M, GlobalVariable *BinDesc) {
+ LLVMContext &C = M.getContext();
+ auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
+ auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
+ ".omp_offloading.descriptor_unreg", &M);
+ Func->setSection(".text.startup");
+
+ // Get __tgt_unregister_lib function declaration.
+ auto *UnRegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(M),
+ /*isVarArg*/ false);
+ FunctionCallee UnRegFuncC =
+ M.getOrInsertFunction("__tgt_unregister_lib", UnRegFuncTy);
+
+ // Construct function body
+ IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
+ Builder.CreateCall(UnRegFuncC, BinDesc);
+ Builder.CreateRetVoid();
+
+ // Add this function to global destructors.
+ // Match priority of __tgt_register_lib
+ appendToGlobalDtors(M, Func, /*Priority*/ 1);
+}
+
+// struct fatbin_wrapper {
+// int32_t magic;
+// int32_t version;
+// void *image;
+// void *reserved;
+//};
+StructType *getFatbinWrapperTy(Module &M) {
+ LLVMContext &C = M.getContext();
+ StructType *FatbinTy = StructType::getTypeByName(C, "fatbin_wrapper");
+ if (!FatbinTy)
+ FatbinTy = StructType::create("fatbin_wrapper", Type::getInt32Ty(C),
+ Type::getInt32Ty(C), Type::getInt8PtrTy(C),
+ Type::getInt8PtrTy(C));
+ return FatbinTy;
+}
+
+/// Embed the image \p Image into the module \p M so it can be found by the
+/// runtime.
+GlobalVariable *createFatbinDesc(Module &M, ArrayRef<char> Image, bool IsHIP) {
+ LLVMContext &C = M.getContext();
+ llvm::Type *Int8PtrTy = Type::getInt8PtrTy(C);
+ llvm::Triple Triple = llvm::Triple(M.getTargetTriple());
+
+ // Create the global string containing the fatbinary.
+ StringRef FatbinConstantSection =
+ IsHIP ? ".hip_fatbin"
+ : (Triple.isMacOSX() ? "__NV_CUDA,__nv_fatbin" : ".nv_fatbin");
+ auto *Data = ConstantDataArray::get(C, Image);
+ auto *Fatbin = new GlobalVariable(M, Data->getType(), /*isConstant*/ true,
+ GlobalVariable::InternalLinkage, Data,
+ ".fatbin_image");
+ Fatbin->setSection(FatbinConstantSection);
+
+ // Create the fatbinary wrapper
+ StringRef FatbinWrapperSection = IsHIP ? ".hipFatBinSegment"
+ : Triple.isMacOSX() ? "__NV_CUDA,__fatbin"
+ : ".nvFatBinSegment";
+ Constant *FatbinWrapper[] = {
+ ConstantInt::get(Type::getInt32Ty(C), IsHIP ? HIPFatMagic : CudaFatMagic),
+ ConstantInt::get(Type::getInt32Ty(C), 1),
+ ConstantExpr::getPointerBitCastOrAddrSpaceCast(Fatbin, Int8PtrTy),
+ ConstantPointerNull::get(Type::getInt8PtrTy(C))};
+
+ Constant *FatbinInitializer =
+ ConstantStruct::get(getFatbinWrapperTy(M), FatbinWrapper);
+
+ auto *FatbinDesc =
+ new GlobalVariable(M, getFatbinWrapperTy(M),
+ /*isConstant*/ true, GlobalValue::InternalLinkage,
+ FatbinInitializer, ".fatbin_wrapper");
+ FatbinDesc->setSection(FatbinWrapperSection);
+ FatbinDesc->setAlignment(Align(8));
+
+ // We create a dummy entry to ensure the linker will define the begin / end
+ // symbols. The CUDA runtime should ignore the null address if we attempt to
+ // register it.
+ auto *DummyInit =
+ ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u));
+ auto *DummyEntry = new GlobalVariable(
+ M, DummyInit->getType(), true, GlobalVariable::ExternalLinkage, DummyInit,
+ IsHIP ? "__dummy.hip_offloading.entry" : "__dummy.cuda_offloading.entry");
+ DummyEntry->setVisibility(GlobalValue::HiddenVisibility);
+ DummyEntry->setSection(IsHIP ? "hip_offloading_entries"
+ : "cuda_offloading_entries");
+
+ return FatbinDesc;
+}
+
+/// Create the register globals function. We will iterate all of the offloading
+/// entries stored at the begin / end symbols and register them according to
+/// their type. This creates the following function in IR:
+///
+/// extern struct __tgt_offload_entry __start_cuda_offloading_entries;
+/// extern struct __tgt_offload_entry __stop_cuda_offloading_entries;
+///
+/// extern void __cudaRegisterFunction(void **, void *, void *, void *, int,
+/// void *, void *, void *, void *, int *);
+/// extern void __cudaRegisterVar(void **, void *, void *, void *, int32_t,
+/// int64_t, int32_t, int32_t);
+///
+/// void __cudaRegisterTest(void **fatbinHandle) {
+/// for (struct __tgt_offload_entry *entry = &__start_cuda_offloading_entries;
+/// entry != &__stop_cuda_offloading_entries; ++entry) {
+/// if (!entry->size)
+/// __cudaRegisterFunction(fatbinHandle, entry->addr, entry->name,
+/// entry->name, -1, 0, 0, 0, 0, 0);
+/// else
+/// __cudaRegisterVar(fatbinHandle, entry->addr, entry->name, entry->name,
+/// 0, entry->size, 0, 0);
+/// }
+/// }
+Function *createRegisterGlobalsFunction(Module &M, bool IsHIP) {
+ LLVMContext &C = M.getContext();
+ // Get the __cudaRegisterFunction function declaration.
+ auto *RegFuncTy = FunctionType::get(
+ Type::getInt32Ty(C),
+ {Type::getInt8PtrTy(C)->getPointerTo(), Type::getInt8PtrTy(C),
+ Type::getInt8PtrTy(C), Type::getInt8PtrTy(C), Type::getInt32Ty(C),
+ Type::getInt8PtrTy(C), Type::getInt8PtrTy(C), Type::getInt8PtrTy(C),
+ Type::getInt8PtrTy(C), Type::getInt32PtrTy(C)},
+ /*isVarArg*/ false);
+ FunctionCallee RegFunc = M.getOrInsertFunction(
+ IsHIP ? "__hipRegisterFunction" : "__cudaRegisterFunction", RegFuncTy);
+
+ // Get the __cudaRegisterVar function declaration.
+ auto *RegVarTy = FunctionType::get(
+ Type::getVoidTy(C),
+ {Type::getInt8PtrTy(C)->getPointerTo(), Type::getInt8PtrTy(C),
+ Type::getInt8PtrTy(C), Type::getInt8PtrTy(C), Type::getInt32Ty(C),
+ getSizeTTy(M), Type::getInt32Ty(C), Type::getInt32Ty(C)},
+ /*isVarArg*/ false);
+ FunctionCallee RegVar = M.getOrInsertFunction(
+ IsHIP ? "__hipRegisterVar" : "__cudaRegisterVar", RegVarTy);
+
+ // Create the references to the start / stop symbols defined by the linker.
+ auto *EntriesB =
+ new GlobalVariable(M, ArrayType::get(getEntryTy(M), 0),
+ /*isConstant*/ true, GlobalValue::ExternalLinkage,
+ /*Initializer*/ nullptr,
+ IsHIP ? "__start_hip_offloading_entries"
+ : "__start_cuda_offloading_entries");
+ EntriesB->setVisibility(GlobalValue::HiddenVisibility);
+ auto *EntriesE =
+ new GlobalVariable(M, ArrayType::get(getEntryTy(M), 0),
+ /*isConstant*/ true, GlobalValue::ExternalLinkage,
+ /*Initializer*/ nullptr,
+ IsHIP ? "__stop_hip_offloading_entries"
+ : "__stop_cuda_offloading_entries");
+ EntriesE->setVisibility(GlobalValue::HiddenVisibility);
+
+ auto *RegGlobalsTy = FunctionType::get(Type::getVoidTy(C),
+ Type::getInt8PtrTy(C)->getPointerTo(),
+ /*isVarArg*/ false);
+ auto *RegGlobalsFn =
+ Function::Create(RegGlobalsTy, GlobalValue::InternalLinkage,
+ IsHIP ? ".hip.globals_reg" : ".cuda.globals_reg", &M);
+ RegGlobalsFn->setSection(".text.startup");
+
+ // Create the loop to register all the entries.
+ IRBuilder<> Builder(BasicBlock::Create(C, "entry", RegGlobalsFn));
+ auto *EntryBB = BasicBlock::Create(C, "while.entry", RegGlobalsFn);
+ auto *IfThenBB = BasicBlock::Create(C, "if.then", RegGlobalsFn);
+ auto *IfElseBB = BasicBlock::Create(C, "if.else", RegGlobalsFn);
+ auto *SwGlobalBB = BasicBlock::Create(C, "sw.global", RegGlobalsFn);
+ auto *SwManagedBB = BasicBlock::Create(C, "sw.managed", RegGlobalsFn);
+ auto *SwSurfaceBB = BasicBlock::Create(C, "sw.surface", RegGlobalsFn);
+ auto *SwTextureBB = BasicBlock::Create(C, "sw.texture", RegGlobalsFn);
+ auto *IfEndBB = BasicBlock::Create(C, "if.end", RegGlobalsFn);
+ auto *ExitBB = BasicBlock::Create(C, "while.end", RegGlobalsFn);
+
+ auto *EntryCmp = Builder.CreateICmpNE(EntriesB, EntriesE);
+ Builder.CreateCondBr(EntryCmp, EntryBB, ExitBB);
+ Builder.SetInsertPoint(EntryBB);
+ auto *Entry = Builder.CreatePHI(getEntryPtrTy(M), 2, "entry");
+ auto *AddrPtr =
+ Builder.CreateInBoundsGEP(getEntryTy(M), Entry,
+ {ConstantInt::get(getSizeTTy(M), 0),
+ ConstantInt::get(Type::getInt32Ty(C), 0)});
+ auto *Addr = Builder.CreateLoad(Type::getInt8PtrTy(C), AddrPtr, "addr");
+ auto *NamePtr =
+ Builder.CreateInBoundsGEP(getEntryTy(M), Entry,
+ {ConstantInt::get(getSizeTTy(M), 0),
+ ConstantInt::get(Type::getInt32Ty(C), 1)});
+ auto *Name = Builder.CreateLoad(Type::getInt8PtrTy(C), NamePtr, "name");
+ auto *SizePtr =
+ Builder.CreateInBoundsGEP(getEntryTy(M), Entry,
+ {ConstantInt::get(getSizeTTy(M), 0),
+ ConstantInt::get(Type::getInt32Ty(C), 2)});
+ auto *Size = Builder.CreateLoad(getSizeTTy(M), SizePtr, "size");
+ auto *FlagsPtr =
+ Builder.CreateInBoundsGEP(getEntryTy(M), Entry,
+ {ConstantInt::get(getSizeTTy(M), 0),
+ ConstantInt::get(Type::getInt32Ty(C), 3)});
+ auto *Flags = Builder.CreateLoad(Type::getInt32Ty(C), FlagsPtr, "flag");
+ auto *FnCond =
+ Builder.CreateICmpEQ(Size, ConstantInt::getNullValue(getSizeTTy(M)));
+ Builder.CreateCondBr(FnCond, IfThenBB, IfElseBB);
+
+ // Create kernel registration code.
+ Builder.SetInsertPoint(IfThenBB);
+ Builder.CreateCall(RegFunc,
+ {RegGlobalsFn->arg_begin(), Addr, Name, Name,
+ ConstantInt::get(Type::getInt32Ty(C), -1),
+ ConstantPointerNull::get(Type::getInt8PtrTy(C)),
+ ConstantPointerNull::get(Type::getInt8PtrTy(C)),
+ ConstantPointerNull::get(Type::getInt8PtrTy(C)),
+ ConstantPointerNull::get(Type::getInt8PtrTy(C)),
+ ConstantPointerNull::get(Type::getInt32PtrTy(C))});
+ Builder.CreateBr(IfEndBB);
+ Builder.SetInsertPoint(IfElseBB);
+
+ auto *Switch = Builder.CreateSwitch(Flags, IfEndBB);
+ // Create global variable registration code.
+ Builder.SetInsertPoint(SwGlobalBB);
+ Builder.CreateCall(RegVar, {RegGlobalsFn->arg_begin(), Addr, Name, Name,
+ ConstantInt::get(Type::getInt32Ty(C), 0), Size,
+ ConstantInt::get(Type::getInt32Ty(C), 0),
+ ConstantInt::get(Type::getInt32Ty(C), 0)});
+ Builder.CreateBr(IfEndBB);
+ Switch->addCase(Builder.getInt32(OffloadGlobalEntry), SwGlobalBB);
+
+ // Create managed variable registration code.
+ Builder.SetInsertPoint(SwManagedBB);
+ Builder.CreateBr(IfEndBB);
+ Switch->addCase(Builder.getInt32(OffloadGlobalManagedEntry), SwManagedBB);
+
+ // Create surface variable registration code.
+ Builder.SetInsertPoint(SwSurfaceBB);
+ Builder.CreateBr(IfEndBB);
+ Switch->addCase(Builder.getInt32(OffloadGlobalSurfaceEntry), SwSurfaceBB);
+
+ // Create texture variable registration code.
+ Builder.SetInsertPoint(SwTextureBB);
+ Builder.CreateBr(IfEndBB);
+ Switch->addCase(Builder.getInt32(OffloadGlobalTextureEntry), SwTextureBB);
+
+ Builder.SetInsertPoint(IfEndBB);
+ auto *NewEntry = Builder.CreateInBoundsGEP(
+ getEntryTy(M), Entry, ConstantInt::get(getSizeTTy(M), 1));
+ auto *Cmp = Builder.CreateICmpEQ(
+ NewEntry,
+ ConstantExpr::getInBoundsGetElementPtr(
+ ArrayType::get(getEntryTy(M), 0), EntriesE,
+ ArrayRef<Constant *>({ConstantInt::get(getSizeTTy(M), 0),
+ ConstantInt::get(getSizeTTy(M), 0)})));
+ Entry->addIncoming(
+ ConstantExpr::getInBoundsGetElementPtr(
+ ArrayType::get(getEntryTy(M), 0), EntriesB,
+ ArrayRef<Constant *>({ConstantInt::get(getSizeTTy(M), 0),
+ ConstantInt::get(getSizeTTy(M), 0)})),
+ &RegGlobalsFn->getEntryBlock());
+ Entry->addIncoming(NewEntry, IfEndBB);
+ Builder.CreateCondBr(Cmp, ExitBB, EntryBB);
+ Builder.SetInsertPoint(ExitBB);
+ Builder.CreateRetVoid();
+
+ return RegGlobalsFn;
+}
+
+// Create the constructor and destructor to register the fatbinary with the CUDA
+// runtime.
+void createRegisterFatbinFunction(Module &M, GlobalVariable *FatbinDesc,
+ bool IsHIP) {
+ LLVMContext &C = M.getContext();
+ auto *CtorFuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
+ auto *CtorFunc =
+ Function::Create(CtorFuncTy, GlobalValue::InternalLinkage,
+ IsHIP ? ".hip.fatbin_reg" : ".cuda.fatbin_reg", &M);
+ CtorFunc->setSection(".text.startup");
+
+ auto *DtorFuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
+ auto *DtorFunc =
+ Function::Create(DtorFuncTy, GlobalValue::InternalLinkage,
+ IsHIP ? ".hip.fatbin_unreg" : ".cuda.fatbin_unreg", &M);
+ DtorFunc->setSection(".text.startup");
+
+ // Get the __cudaRegisterFatBinary function declaration.
+ auto *RegFatTy = FunctionType::get(Type::getInt8PtrTy(C)->getPointerTo(),
+ Type::getInt8PtrTy(C),
+ /*isVarArg*/ false);
+ FunctionCallee RegFatbin = M.getOrInsertFunction(
+ IsHIP ? "__hipRegisterFatBinary" : "__cudaRegisterFatBinary", RegFatTy);
+ // Get the __cudaRegisterFatBinaryEnd function declaration.
+ auto *RegFatEndTy = FunctionType::get(Type::getVoidTy(C),
+ Type::getInt8PtrTy(C)->getPointerTo(),
+ /*isVarArg*/ false);
+ FunctionCallee RegFatbinEnd =
+ M.getOrInsertFunction("__cudaRegisterFatBinaryEnd", RegFatEndTy);
+ // Get the __cudaUnregisterFatBinary function declaration.
+ auto *UnregFatTy = FunctionType::get(Type::getVoidTy(C),
+ Type::getInt8PtrTy(C)->getPointerTo(),
+ /*isVarArg*/ false);
+ FunctionCallee UnregFatbin = M.getOrInsertFunction(
+ IsHIP ? "__hipUnregisterFatBinary" : "__cudaUnregisterFatBinary",
+ UnregFatTy);
+
+ auto *AtExitTy =
+ FunctionType::get(Type::getInt32Ty(C), DtorFuncTy->getPointerTo(),
+ /*isVarArg*/ false);
+ FunctionCallee AtExit = M.getOrInsertFunction("atexit", AtExitTy);
+
+ auto *BinaryHandleGlobal = new llvm::GlobalVariable(
+ M, Type::getInt8PtrTy(C)->getPointerTo(), false,
+ llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantPointerNull::get(Type::getInt8PtrTy(C)->getPointerTo()),
+ IsHIP ? ".hip.binary_handle" : ".cuda.binary_handle");
+
+ // Create the constructor to register this image with the runtime.
+ IRBuilder<> CtorBuilder(BasicBlock::Create(C, "entry", CtorFunc));
+ CallInst *Handle = CtorBuilder.CreateCall(
+ RegFatbin, ConstantExpr::getPointerBitCastOrAddrSpaceCast(
+ FatbinDesc, Type::getInt8PtrTy(C)));
+ CtorBuilder.CreateAlignedStore(
+ Handle, BinaryHandleGlobal,
+ Align(M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))));
+ CtorBuilder.CreateCall(createRegisterGlobalsFunction(M, IsHIP), Handle);
+ if (!IsHIP)
+ CtorBuilder.CreateCall(RegFatbinEnd, Handle);
+ CtorBuilder.CreateCall(AtExit, DtorFunc);
+ CtorBuilder.CreateRetVoid();
+
+ // Create the destructor to unregister the image with the runtime. We cannot
+ // use a standard global destructor after CUDA 9.2 so this must be called by
+ // `atexit()` intead.
+ IRBuilder<> DtorBuilder(BasicBlock::Create(C, "entry", DtorFunc));
+ LoadInst *BinaryHandle = DtorBuilder.CreateAlignedLoad(
+ Type::getInt8PtrTy(C)->getPointerTo(), BinaryHandleGlobal,
+ Align(M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))));
+ DtorBuilder.CreateCall(UnregFatbin, BinaryHandle);
+ DtorBuilder.CreateRetVoid();
+
+ // Add this function to constructors.
+ appendToGlobalCtors(M, CtorFunc, /*Priority*/ 1);
+}
+
+} // namespace
+
+Error wrapOpenMPBinaries(Module &M, ArrayRef<ArrayRef<char>> Images) {
+ GlobalVariable *Desc = createBinDesc(M, Images);
+ if (!Desc)
+ return createStringError(inconvertibleErrorCode(),
+ "No binary descriptors created.");
+ createRegisterFunction(M, Desc);
+ createUnregisterFunction(M, Desc);
+ return Error::success();
+}
+
+Error wrapCudaBinary(Module &M, ArrayRef<char> Image) {
+ GlobalVariable *Desc = createFatbinDesc(M, Image, /* IsHIP */ false);
+ if (!Desc)
+ return createStringError(inconvertibleErrorCode(),
+ "No fatinbary section created.");
+
+ createRegisterFatbinFunction(M, Desc, /* IsHIP */ false);
+ return Error::success();
+}
+
+Error wrapHIPBinary(Module &M, ArrayRef<char> Image) {
+ GlobalVariable *Desc = createFatbinDesc(M, Image, /* IsHIP */ true);
+ if (!Desc)
+ return createStringError(inconvertibleErrorCode(),
+ "No fatinbary section created.");
+
+ createRegisterFatbinFunction(M, Desc, /* IsHIP */ true);
+ return Error::success();
+}
diff --git a/gnu/llvm/clang/tools/clang-linker-wrapper/OffloadWrapper.h b/gnu/llvm/clang/tools/clang-linker-wrapper/OffloadWrapper.h
new file mode 100644
index 00000000000..679333975b2
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-linker-wrapper/OffloadWrapper.h
@@ -0,0 +1,28 @@
+//===- OffloadWrapper.h --r-------------------------------------*- C++ -*-===//
+//
+// 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 LLVM_CLANG_TOOLS_CLANG_LINKER_WRAPPER_OFFLOAD_WRAPPER_H
+#define LLVM_CLANG_TOOLS_CLANG_LINKER_WRAPPER_OFFLOAD_WRAPPER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/Module.h"
+
+/// Wraps the input device images into the module \p M as global symbols and
+/// registers the images with the OpenMP Offloading runtime libomptarget.
+llvm::Error wrapOpenMPBinaries(llvm::Module &M,
+ llvm::ArrayRef<llvm::ArrayRef<char>> Images);
+
+/// Wraps the input fatbinary image into the module \p M as global symbols and
+/// registers the images with the CUDA runtime.
+llvm::Error wrapCudaBinary(llvm::Module &M, llvm::ArrayRef<char> Images);
+
+/// Wraps the input bundled image into the module \p M as global symbols and
+/// registers the images with the HIP runtime.
+llvm::Error wrapHIPBinary(llvm::Module &M, llvm::ArrayRef<char> Images);
+
+#endif
diff --git a/gnu/llvm/clang/tools/clang-offload-bundler/CMakeLists.txt b/gnu/llvm/clang/tools/clang-offload-bundler/CMakeLists.txt
index 2738bf02e72..7bc22f1479d 100644
--- a/gnu/llvm/clang/tools/clang-offload-bundler/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-offload-bundler/CMakeLists.txt
@@ -1,16 +1,21 @@
-set(LLVM_LINK_COMPONENTS Object Support)
+set(LLVM_LINK_COMPONENTS
+ Object
+ Support
+ TargetParser
+ )
add_clang_tool(clang-offload-bundler
ClangOffloadBundler.cpp
-
+
DEPENDS
intrinsics_gen
)
set(CLANG_OFFLOAD_BUNDLER_LIB_DEPS
clangBasic
+ clangDriver
)
-
+
add_dependencies(clang clang-offload-bundler)
clang_target_link_libraries(clang-offload-bundler
diff --git a/gnu/llvm/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/gnu/llvm/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
index 43f7091c97f..04ad545f19c 100644
--- a/gnu/llvm/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
+++ b/gnu/llvm/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp
@@ -7,20 +7,20 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// This file implements a clang-offload-bundler that bundles different
-/// files that relate with the same source code but different targets into a
-/// single one. Also the implements the opposite functionality, i.e. unbundle
-/// files previous created by this tool.
+/// This file implements a stand-alone clang-offload-bundler tool using the
+/// OffloadBundler API.
///
//===----------------------------------------------------------------------===//
+#include "clang/Basic/Cuda.h"
+#include "clang/Basic/TargetID.h"
#include "clang/Basic/Version.h"
+#include "clang/Driver/OffloadBundler.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
@@ -46,6 +46,7 @@
#include <cstddef>
#include <cstdint>
#include <forward_list>
+#include <map>
#include <memory>
#include <set>
#include <string>
@@ -54,1242 +55,89 @@
using namespace llvm;
using namespace llvm::object;
+using namespace clang;
-static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+static void PrintVersion(raw_ostream &OS) {
+ OS << clang::getClangToolFullVersion("clang-offload-bundler") << '\n';
+}
-// Mark all our options with this category, everything else (except for -version
-// and -help) will be hidden.
-static cl::OptionCategory
- ClangOffloadBundlerCategory("clang-offload-bundler options");
+int main(int argc, const char **argv) {
+
+ cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
-static cl::list<std::string>
- InputFileNames("inputs", cl::CommaSeparated, cl::OneOrMore,
- cl::desc("[<input file>,...]"),
+ // Mark all our options with this category, everything else (except for
+ // -version and -help) will be hidden.
+ cl::OptionCategory
+ ClangOffloadBundlerCategory("clang-offload-bundler options");
+ cl::list<std::string>
+ InputFileNames("input",
+ cl::desc("Input file."
+ " Can be specified multiple times "
+ "for multiple input files."),
cl::cat(ClangOffloadBundlerCategory));
-static cl::list<std::string>
- OutputFileNames("outputs", cl::CommaSeparated,
- cl::desc("[<output file>,...]"),
+ cl::list<std::string>
+ InputFileNamesDeprecatedOpt("inputs", cl::CommaSeparated,
+ cl::desc("[<input file>,...] (deprecated)"),
+ cl::cat(ClangOffloadBundlerCategory));
+ cl::list<std::string>
+ OutputFileNames("output",
+ cl::desc("Output file."
+ " Can be specified multiple times "
+ "for multiple output files."),
cl::cat(ClangOffloadBundlerCategory));
-static cl::list<std::string>
+ cl::list<std::string>
+ OutputFileNamesDeprecatedOpt("outputs", cl::CommaSeparated,
+ cl::desc("[<output file>,...] (deprecated)"),
+ cl::cat(ClangOffloadBundlerCategory));
+ cl::list<std::string>
TargetNames("targets", cl::CommaSeparated,
cl::desc("[<offload kind>-<target triple>,...]"),
cl::cat(ClangOffloadBundlerCategory));
-static cl::opt<std::string>
- FilesType("type", cl::Required,
- cl::desc("Type of the files to be bundled/unbundled.\n"
- "Current supported types are:\n"
- " i - cpp-output\n"
- " ii - c++-cpp-output\n"
- " cui - cuda/hip-output\n"
- " d - dependency\n"
- " ll - llvm\n"
- " bc - llvm-bc\n"
- " s - assembler\n"
- " o - object\n"
- " a - archive of objects\n"
- " gch - precompiled-header\n"
- " ast - clang AST file"),
- cl::cat(ClangOffloadBundlerCategory));
-static cl::opt<bool>
+ cl::opt<std::string> FilesType(
+ "type", cl::Required,
+ cl::desc("Type of the files to be bundled/unbundled.\n"
+ "Current supported types are:\n"
+ " i - cpp-output\n"
+ " ii - c++-cpp-output\n"
+ " cui - cuda-cpp-output\n"
+ " hipi - hip-cpp-output\n"
+ " d - dependency\n"
+ " ll - llvm\n"
+ " bc - llvm-bc\n"
+ " s - assembler\n"
+ " o - object\n"
+ " a - archive of objects\n"
+ " gch - precompiled-header\n"
+ " ast - clang AST file"),
+ cl::cat(ClangOffloadBundlerCategory));
+ cl::opt<bool>
Unbundle("unbundle",
cl::desc("Unbundle bundled file into several output files.\n"),
cl::init(false), cl::cat(ClangOffloadBundlerCategory));
-
-static cl::opt<bool>
+ cl::opt<bool>
ListBundleIDs("list", cl::desc("List bundle IDs in the bundled file.\n"),
cl::init(false), cl::cat(ClangOffloadBundlerCategory));
-
-static cl::opt<bool> PrintExternalCommands(
+ cl::opt<bool> PrintExternalCommands(
"###",
cl::desc("Print any external commands that are to be executed "
"instead of actually executing them - for testing purposes.\n"),
cl::init(false), cl::cat(ClangOffloadBundlerCategory));
-
-static cl::opt<bool>
+ cl::opt<bool>
AllowMissingBundles("allow-missing-bundles",
cl::desc("Create empty files if bundles are missing "
"when unbundling.\n"),
cl::init(false), cl::cat(ClangOffloadBundlerCategory));
-
-static cl::opt<unsigned>
+ cl::opt<unsigned>
BundleAlignment("bundle-align",
cl::desc("Alignment of bundle for binary files"),
cl::init(1), cl::cat(ClangOffloadBundlerCategory));
+ cl::opt<bool> HipOpenmpCompatible(
+ "hip-openmp-compatible",
+ cl::desc("Treat hip and hipv4 offload kinds as "
+ "compatible with openmp kind, and vice versa.\n"),
+ cl::init(false), cl::cat(ClangOffloadBundlerCategory));
-/// Magic string that marks the existence of offloading data.
-#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
-
-/// The index of the host input in the list of inputs.
-static unsigned HostInputIndex = ~0u;
-
-/// Whether not having host target is allowed.
-static bool AllowNoHost = false;
-
-/// Path to the current binary.
-static std::string BundlerExecutable;
-
-/// Obtain the offload kind, real machine triple, and an optional GPUArch
-/// out of the target information specified by the user.
-/// Bundle Entry ID (or, Offload Target String) has following components:
-/// * Offload Kind - Host, OpenMP, or HIP
-/// * Triple - Standard LLVM Triple
-/// * GPUArch (Optional) - Processor name, like gfx906 or sm_30
-/// In presence of Proc, the Triple should contain separator "-" for all
-/// standard four components, even if they are empty.
-struct OffloadTargetInfo {
- StringRef OffloadKind;
- llvm::Triple Triple;
- StringRef GPUArch;
-
- OffloadTargetInfo(const StringRef Target) {
- SmallVector<StringRef, 6> Components;
- Target.split(Components, '-', 5);
- Components.resize(6);
- this->OffloadKind = Components[0];
- this->Triple = llvm::Triple(Components[1], Components[2], Components[3],
- Components[4]);
- this->GPUArch = Components[5];
- }
-
- bool hasHostKind() const { return this->OffloadKind == "host"; }
-
- bool isOffloadKindValid() const {
- return OffloadKind == "host" || OffloadKind == "openmp" ||
- OffloadKind == "hip" || OffloadKind == "hipv4";
- }
-
- bool isTripleValid() const {
- return !Triple.str().empty() && Triple.getArch() != Triple::UnknownArch;
- }
-
- bool operator==(const OffloadTargetInfo &Target) const {
- return OffloadKind == Target.OffloadKind &&
- Triple.isCompatibleWith(Target.Triple) && GPUArch == Target.GPUArch;
- }
-
- std::string str() {
- return Twine(OffloadKind + "-" + Triple.str() + "-" + GPUArch).str();
- }
-};
-
-/// Generic file handler interface.
-class FileHandler {
-public:
- struct BundleInfo {
- StringRef BundleID;
- };
-
- FileHandler() {}
-
- virtual ~FileHandler() {}
-
- /// Update the file handler with information from the header of the bundled
- /// file.
- virtual Error ReadHeader(MemoryBuffer &Input) = 0;
-
- /// Read the marker of the next bundled to be read in the file. The bundle
- /// name is returned if there is one in the file, or `None` if there are no
- /// more bundles to be read.
- virtual Expected<Optional<StringRef>>
- ReadBundleStart(MemoryBuffer &Input) = 0;
-
- /// Read the marker that closes the current bundle.
- virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
-
- /// Read the current bundle and write the result into the stream \a OS.
- virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
-
- /// Write the header of the bundled file to \a OS based on the information
- /// gathered from \a Inputs.
- virtual Error WriteHeader(raw_fd_ostream &OS,
- ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
-
- /// Write the marker that initiates a bundle for the triple \a TargetTriple to
- /// \a OS.
- virtual Error WriteBundleStart(raw_fd_ostream &OS,
- StringRef TargetTriple) = 0;
-
- /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
- /// OS.
- virtual Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
-
- /// Write the bundle from \a Input into \a OS.
- virtual Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
-
- /// List bundle IDs in \a Input.
- virtual Error listBundleIDs(MemoryBuffer &Input) {
- if (Error Err = ReadHeader(Input))
- return Err;
-
- return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
- llvm::outs() << Info.BundleID << '\n';
- Error Err = listBundleIDsCallback(Input, Info);
- if (Err)
- return Err;
- return Error::success();
- });
- }
-
- /// For each bundle in \a Input, do \a Func.
- Error forEachBundle(MemoryBuffer &Input,
- std::function<Error(const BundleInfo &)> Func) {
- while (true) {
- Expected<Optional<StringRef>> CurTripleOrErr = ReadBundleStart(Input);
- if (!CurTripleOrErr)
- return CurTripleOrErr.takeError();
-
- // No more bundles.
- if (!*CurTripleOrErr)
- break;
-
- StringRef CurTriple = **CurTripleOrErr;
- assert(!CurTriple.empty());
-
- BundleInfo Info{CurTriple};
- if (Error Err = Func(Info))
- return Err;
- }
- return Error::success();
- }
-
-protected:
- virtual Error listBundleIDsCallback(MemoryBuffer &Input,
- const BundleInfo &Info) {
- return Error::success();
- }
-};
-
-/// Handler for binary files. The bundled file will have the following format
-/// (all integers are stored in little-endian format):
-///
-/// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
-///
-/// NumberOfOffloadBundles (8-byte integer)
-///
-/// OffsetOfBundle1 (8-byte integer)
-/// SizeOfBundle1 (8-byte integer)
-/// NumberOfBytesInTripleOfBundle1 (8-byte integer)
-/// TripleOfBundle1 (byte length defined before)
-///
-/// ...
-///
-/// OffsetOfBundleN (8-byte integer)
-/// SizeOfBundleN (8-byte integer)
-/// NumberOfBytesInTripleOfBundleN (8-byte integer)
-/// TripleOfBundleN (byte length defined before)
-///
-/// Bundle1
-/// ...
-/// BundleN
-
-/// Read 8-byte integers from a buffer in little-endian format.
-static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
- uint64_t Res = 0;
- const char *Data = Buffer.data();
-
- for (unsigned i = 0; i < 8; ++i) {
- Res <<= 8;
- uint64_t Char = (uint64_t)Data[pos + 7 - i];
- Res |= 0xffu & Char;
- }
- return Res;
-}
-
-/// Write 8-byte integers to a buffer in little-endian format.
-static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) {
- for (unsigned i = 0; i < 8; ++i) {
- char Char = (char)(Val & 0xffu);
- OS.write(&Char, 1);
- Val >>= 8;
- }
-}
-
-class BinaryFileHandler final : public FileHandler {
- /// Information about the bundles extracted from the header.
- struct BinaryBundleInfo final : public BundleInfo {
- /// Size of the bundle.
- uint64_t Size = 0u;
- /// Offset at which the bundle starts in the bundled file.
- uint64_t Offset = 0u;
-
- BinaryBundleInfo() {}
- BinaryBundleInfo(uint64_t Size, uint64_t Offset)
- : Size(Size), Offset(Offset) {}
- };
-
- /// Map between a triple and the corresponding bundle information.
- StringMap<BinaryBundleInfo> BundlesInfo;
-
- /// Iterator for the bundle information that is being read.
- StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
- StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
-
- /// Current bundle target to be written.
- std::string CurWriteBundleTarget;
-
-public:
- BinaryFileHandler() : FileHandler() {}
-
- ~BinaryFileHandler() final {}
-
- Error ReadHeader(MemoryBuffer &Input) final {
- StringRef FC = Input.getBuffer();
-
- // Initialize the current bundle with the end of the container.
- CurBundleInfo = BundlesInfo.end();
-
- // Check if buffer is smaller than magic string.
- size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
- if (ReadChars > FC.size())
- return Error::success();
-
- // Check if no magic was found.
- StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
- if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
- return Error::success();
-
- // Read number of bundles.
- if (ReadChars + 8 > FC.size())
- return Error::success();
-
- uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
- ReadChars += 8;
-
- // Read bundle offsets, sizes and triples.
- for (uint64_t i = 0; i < NumberOfBundles; ++i) {
-
- // Read offset.
- if (ReadChars + 8 > FC.size())
- return Error::success();
-
- uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
- ReadChars += 8;
-
- // Read size.
- if (ReadChars + 8 > FC.size())
- return Error::success();
-
- uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
- ReadChars += 8;
-
- // Read triple size.
- if (ReadChars + 8 > FC.size())
- return Error::success();
-
- uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
- ReadChars += 8;
-
- // Read triple.
- if (ReadChars + TripleSize > FC.size())
- return Error::success();
-
- StringRef Triple(&FC.data()[ReadChars], TripleSize);
- ReadChars += TripleSize;
-
- // Check if the offset and size make sense.
- if (!Offset || Offset + Size > FC.size())
- return Error::success();
-
- assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
- "Triple is duplicated??");
- BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
- }
- // Set the iterator to where we will start to read.
- CurBundleInfo = BundlesInfo.end();
- NextBundleInfo = BundlesInfo.begin();
- return Error::success();
- }
-
- Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
- if (NextBundleInfo == BundlesInfo.end())
- return None;
- CurBundleInfo = NextBundleInfo++;
- return CurBundleInfo->first();
- }
-
- Error ReadBundleEnd(MemoryBuffer &Input) final {
- assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
- return Error::success();
- }
-
- Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
- assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
- StringRef FC = Input.getBuffer();
- OS.write(FC.data() + CurBundleInfo->second.Offset,
- CurBundleInfo->second.Size);
- return Error::success();
- }
-
- Error WriteHeader(raw_fd_ostream &OS,
- ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
- // Compute size of the header.
- uint64_t HeaderSize = 0;
-
- HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
- HeaderSize += 8; // Number of Bundles
-
- for (auto &T : TargetNames) {
- HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
- HeaderSize += T.size(); // The triple.
- }
-
- // Write to the buffer the header.
- OS << OFFLOAD_BUNDLER_MAGIC_STR;
-
- Write8byteIntegerToBuffer(OS, TargetNames.size());
-
- unsigned Idx = 0;
- for (auto &T : TargetNames) {
- MemoryBuffer &MB = *Inputs[Idx++];
- HeaderSize = alignTo(HeaderSize, BundleAlignment);
- // Bundle offset.
- Write8byteIntegerToBuffer(OS, HeaderSize);
- // Size of the bundle (adds to the next bundle's offset)
- Write8byteIntegerToBuffer(OS, MB.getBufferSize());
- BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
- HeaderSize += MB.getBufferSize();
- // Size of the triple
- Write8byteIntegerToBuffer(OS, T.size());
- // Triple
- OS << T;
- }
- return Error::success();
- }
-
- Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
- CurWriteBundleTarget = TargetTriple.str();
- return Error::success();
- }
-
- Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
- return Error::success();
- }
-
- Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
- auto BI = BundlesInfo[CurWriteBundleTarget];
- OS.seek(BI.Offset);
- OS.write(Input.getBufferStart(), Input.getBufferSize());
- return Error::success();
- }
-};
-
-namespace {
-
-// This class implements a list of temporary files that are removed upon
-// object destruction.
-class TempFileHandlerRAII {
-public:
- ~TempFileHandlerRAII() {
- for (const auto &File : Files)
- sys::fs::remove(File);
- }
-
- // Creates temporary file with given contents.
- Expected<StringRef> Create(Optional<ArrayRef<char>> Contents) {
- SmallString<128u> File;
- if (std::error_code EC =
- sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File))
- return createFileError(File, EC);
- Files.push_front(File);
-
- if (Contents) {
- std::error_code EC;
- raw_fd_ostream OS(File, EC);
- if (EC)
- return createFileError(File, EC);
- OS.write(Contents->data(), Contents->size());
- }
- return Files.front().str();
- }
-
-private:
- std::forward_list<SmallString<128u>> Files;
-};
-
-} // end anonymous namespace
-
-/// Handler for object files. The bundles are organized by sections with a
-/// designated name.
-///
-/// To unbundle, we just copy the contents of the designated section.
-class ObjectFileHandler final : public FileHandler {
-
- /// The object file we are currently dealing with.
- std::unique_ptr<ObjectFile> Obj;
-
- /// Return the input file contents.
- StringRef getInputFileContents() const { return Obj->getData(); }
-
- /// Return bundle name (<kind>-<triple>) if the provided section is an offload
- /// section.
- static Expected<Optional<StringRef>> IsOffloadSection(SectionRef CurSection) {
- Expected<StringRef> NameOrErr = CurSection.getName();
- if (!NameOrErr)
- return NameOrErr.takeError();
-
- // If it does not start with the reserved suffix, just skip this section.
- if (!NameOrErr->startswith(OFFLOAD_BUNDLER_MAGIC_STR))
- return None;
-
- // Return the triple that is right after the reserved prefix.
- return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
- }
-
- /// Total number of inputs.
- unsigned NumberOfInputs = 0;
-
- /// Total number of processed inputs, i.e, inputs that were already
- /// read from the buffers.
- unsigned NumberOfProcessedInputs = 0;
-
- /// Iterator of the current and next section.
- section_iterator CurrentSection;
- section_iterator NextSection;
-
-public:
- ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn)
- : FileHandler(), Obj(std::move(ObjIn)),
- CurrentSection(Obj->section_begin()),
- NextSection(Obj->section_begin()) {}
-
- ~ObjectFileHandler() final {}
-
- Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
-
- Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
- while (NextSection != Obj->section_end()) {
- CurrentSection = NextSection;
- ++NextSection;
-
- // Check if the current section name starts with the reserved prefix. If
- // so, return the triple.
- Expected<Optional<StringRef>> TripleOrErr =
- IsOffloadSection(*CurrentSection);
- if (!TripleOrErr)
- return TripleOrErr.takeError();
- if (*TripleOrErr)
- return **TripleOrErr;
- }
- return None;
- }
-
- Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
-
- Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
- Expected<StringRef> ContentOrErr = CurrentSection->getContents();
- if (!ContentOrErr)
- return ContentOrErr.takeError();
- StringRef Content = *ContentOrErr;
-
- // Copy fat object contents to the output when extracting host bundle.
- if (Content.size() == 1u && Content.front() == 0)
- Content = StringRef(Input.getBufferStart(), Input.getBufferSize());
-
- OS.write(Content.data(), Content.size());
- return Error::success();
- }
-
- Error WriteHeader(raw_fd_ostream &OS,
- ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
- assert(HostInputIndex != ~0u && "Host input index not defined.");
-
- // Record number of inputs.
- NumberOfInputs = Inputs.size();
- return Error::success();
- }
-
- Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
- ++NumberOfProcessedInputs;
- return Error::success();
- }
-
- Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
- assert(NumberOfProcessedInputs <= NumberOfInputs &&
- "Processing more inputs that actually exist!");
- assert(HostInputIndex != ~0u && "Host input index not defined.");
-
- // If this is not the last output, we don't have to do anything.
- if (NumberOfProcessedInputs != NumberOfInputs)
- return Error::success();
-
- // We will use llvm-objcopy to add target objects sections to the output
- // fat object. These sections should have 'exclude' flag set which tells
- // link editor to remove them from linker inputs when linking executable or
- // shared library.
-
- // Find llvm-objcopy in order to create the bundle binary.
- ErrorOr<std::string> Objcopy = sys::findProgramByName(
- "llvm-objcopy", sys::path::parent_path(BundlerExecutable));
- if (!Objcopy)
- Objcopy = sys::findProgramByName("llvm-objcopy");
- if (!Objcopy)
- return createStringError(Objcopy.getError(),
- "unable to find 'llvm-objcopy' in path");
-
- // We write to the output file directly. So, we close it and use the name
- // to pass down to llvm-objcopy.
- OS.close();
-
- // Temporary files that need to be removed.
- TempFileHandlerRAII TempFiles;
-
- // Compose llvm-objcopy command line for add target objects' sections with
- // appropriate flags.
- BumpPtrAllocator Alloc;
- StringSaver SS{Alloc};
- SmallVector<StringRef, 8u> ObjcopyArgs{"llvm-objcopy"};
- for (unsigned I = 0; I < NumberOfInputs; ++I) {
- StringRef InputFile = InputFileNames[I];
- if (I == HostInputIndex) {
- // Special handling for the host bundle. We do not need to add a
- // standard bundle for the host object since we are going to use fat
- // object as a host object. Therefore use dummy contents (one zero byte)
- // when creating section for the host bundle.
- Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
- if (!TempFileOrErr)
- return TempFileOrErr.takeError();
- InputFile = *TempFileOrErr;
- }
-
- ObjcopyArgs.push_back(SS.save(Twine("--add-section=") +
- OFFLOAD_BUNDLER_MAGIC_STR + TargetNames[I] +
- "=" + InputFile));
- ObjcopyArgs.push_back(SS.save(Twine("--set-section-flags=") +
- OFFLOAD_BUNDLER_MAGIC_STR + TargetNames[I] +
- "=readonly,exclude"));
- }
- ObjcopyArgs.push_back("--");
- ObjcopyArgs.push_back(InputFileNames[HostInputIndex]);
- ObjcopyArgs.push_back(OutputFileNames.front());
-
- if (Error Err = executeObjcopy(*Objcopy, ObjcopyArgs))
- return Err;
-
- return Error::success();
- }
-
- Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
- return Error::success();
- }
-
-private:
- static Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
- // If the user asked for the commands to be printed out, we do that
- // instead of executing it.
- if (PrintExternalCommands) {
- errs() << "\"" << Objcopy << "\"";
- for (StringRef Arg : drop_begin(Args, 1))
- errs() << " \"" << Arg << "\"";
- errs() << "\n";
- } else {
- if (sys::ExecuteAndWait(Objcopy, Args))
- return createStringError(inconvertibleErrorCode(),
- "'llvm-objcopy' tool failed");
- }
- return Error::success();
- }
-};
-
-/// Handler for text files. The bundled file will have the following format.
-///
-/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
-/// Bundle 1
-/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
-/// ...
-/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
-/// Bundle N
-/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
-class TextFileHandler final : public FileHandler {
- /// String that begins a line comment.
- StringRef Comment;
-
- /// String that initiates a bundle.
- std::string BundleStartString;
-
- /// String that closes a bundle.
- std::string BundleEndString;
-
- /// Number of chars read from input.
- size_t ReadChars = 0u;
-
-protected:
- Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
-
- Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
- StringRef FC = Input.getBuffer();
-
- // Find start of the bundle.
- ReadChars = FC.find(BundleStartString, ReadChars);
- if (ReadChars == FC.npos)
- return None;
-
- // Get position of the triple.
- size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
-
- // Get position that closes the triple.
- size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
- if (TripleEnd == FC.npos)
- return None;
-
- // Next time we read after the new line.
- ++ReadChars;
-
- return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
- }
-
- Error ReadBundleEnd(MemoryBuffer &Input) final {
- StringRef FC = Input.getBuffer();
-
- // Read up to the next new line.
- assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
-
- size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
- if (TripleEnd != FC.npos)
- // Next time we read after the new line.
- ++ReadChars;
-
- return Error::success();
- }
-
- Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
- StringRef FC = Input.getBuffer();
- size_t BundleStart = ReadChars;
-
- // Find end of the bundle.
- size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
-
- StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
- OS << Bundle;
-
- return Error::success();
- }
-
- Error WriteHeader(raw_fd_ostream &OS,
- ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
- return Error::success();
- }
-
- Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
- OS << BundleStartString << TargetTriple << "\n";
- return Error::success();
- }
-
- Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
- OS << BundleEndString << TargetTriple << "\n";
- return Error::success();
- }
-
- Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
- OS << Input.getBuffer();
- return Error::success();
- }
-
-public:
- TextFileHandler(StringRef Comment)
- : FileHandler(), Comment(Comment), ReadChars(0) {
- BundleStartString =
- "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
- BundleEndString =
- "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
- }
-
- Error listBundleIDsCallback(MemoryBuffer &Input,
- const BundleInfo &Info) final {
- // TODO: To list bundle IDs in a bundled text file we need to go through
- // all bundles. The format of bundled text file may need to include a
- // header if the performance of listing bundle IDs of bundled text file is
- // important.
- ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
- if (Error Err = ReadBundleEnd(Input))
- return Err;
- return Error::success();
- }
-};
-
-/// Return an appropriate object file handler. We use the specific object
-/// handler if we know how to deal with that format, otherwise we use a default
-/// binary file handler.
-static std::unique_ptr<FileHandler>
-CreateObjectFileHandler(MemoryBuffer &FirstInput) {
- // Check if the input file format is one that we know how to deal with.
- Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
-
- // We only support regular object files. If failed to open the input as a
- // known binary or this is not an object file use the default binary handler.
- if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
- return std::make_unique<BinaryFileHandler>();
-
- // Otherwise create an object file handler. The handler will be owned by the
- // client of this function.
- return std::make_unique<ObjectFileHandler>(
- std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())));
-}
-
-/// Return an appropriate handler given the input files and options.
-static Expected<std::unique_ptr<FileHandler>>
-CreateFileHandler(MemoryBuffer &FirstInput) {
- if (FilesType == "i")
- return std::make_unique<TextFileHandler>(/*Comment=*/"//");
- if (FilesType == "ii")
- return std::make_unique<TextFileHandler>(/*Comment=*/"//");
- if (FilesType == "cui")
- return std::make_unique<TextFileHandler>(/*Comment=*/"//");
- // TODO: `.d` should be eventually removed once `-M` and its variants are
- // handled properly in offload compilation.
- if (FilesType == "d")
- return std::make_unique<TextFileHandler>(/*Comment=*/"#");
- if (FilesType == "ll")
- return std::make_unique<TextFileHandler>(/*Comment=*/";");
- if (FilesType == "bc")
- return std::make_unique<BinaryFileHandler>();
- if (FilesType == "s")
- return std::make_unique<TextFileHandler>(/*Comment=*/"#");
- if (FilesType == "o")
- return CreateObjectFileHandler(FirstInput);
- if (FilesType == "a")
- return CreateObjectFileHandler(FirstInput);
- if (FilesType == "gch")
- return std::make_unique<BinaryFileHandler>();
- if (FilesType == "ast")
- return std::make_unique<BinaryFileHandler>();
-
- return createStringError(errc::invalid_argument,
- "'" + FilesType + "': invalid file type specified");
-}
-
-/// Bundle the files. Return true if an error was found.
-static Error BundleFiles() {
- std::error_code EC;
-
- // Create output file.
- raw_fd_ostream OutputFile(OutputFileNames.front(), EC, sys::fs::OF_None);
- if (EC)
- return createFileError(OutputFileNames.front(), EC);
-
- // Open input files.
- SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers;
- InputBuffers.reserve(InputFileNames.size());
- for (auto &I : InputFileNames) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
- MemoryBuffer::getFileOrSTDIN(I);
- if (std::error_code EC = CodeOrErr.getError())
- return createFileError(I, EC);
- InputBuffers.emplace_back(std::move(*CodeOrErr));
- }
-
- // Get the file handler. We use the host buffer as reference.
- assert((HostInputIndex != ~0u || AllowNoHost) &&
- "Host input index undefined??");
- Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
- CreateFileHandler(*InputBuffers[AllowNoHost ? 0 : HostInputIndex]);
- if (!FileHandlerOrErr)
- return FileHandlerOrErr.takeError();
-
- std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
- assert(FH);
-
- // Write header.
- if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
- return Err;
-
- // Write all bundles along with the start/end markers. If an error was found
- // writing the end of the bundle component, abort the bundle writing.
- auto Input = InputBuffers.begin();
- for (auto &Triple : TargetNames) {
- if (Error Err = FH->WriteBundleStart(OutputFile, Triple))
- return Err;
- if (Error Err = FH->WriteBundle(OutputFile, **Input))
- return Err;
- if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
- return Err;
- ++Input;
- }
- return Error::success();
-}
-
-// List bundle IDs. Return true if an error was found.
-static Error ListBundleIDsInFile(StringRef InputFileName) {
- // Open Input file.
- ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
- MemoryBuffer::getFileOrSTDIN(InputFileName);
- if (std::error_code EC = CodeOrErr.getError())
- return createFileError(InputFileName, EC);
-
- MemoryBuffer &Input = **CodeOrErr;
-
- // Select the right files handler.
- Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
- CreateFileHandler(Input);
- if (!FileHandlerOrErr)
- return FileHandlerOrErr.takeError();
-
- std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
- assert(FH);
- return FH->listBundleIDs(Input);
-}
-
-// Unbundle the files. Return true if an error was found.
-static Error UnbundleFiles() {
- // Open Input file.
- ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
- MemoryBuffer::getFileOrSTDIN(InputFileNames.front());
- if (std::error_code EC = CodeOrErr.getError())
- return createFileError(InputFileNames.front(), EC);
-
- MemoryBuffer &Input = **CodeOrErr;
-
- // Select the right files handler.
- Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
- CreateFileHandler(Input);
- if (!FileHandlerOrErr)
- return FileHandlerOrErr.takeError();
-
- std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
- assert(FH);
-
- // Read the header of the bundled file.
- if (Error Err = FH->ReadHeader(Input))
- return Err;
-
- // Create a work list that consist of the map triple/output file.
- StringMap<StringRef> Worklist;
- auto Output = OutputFileNames.begin();
- for (auto &Triple : TargetNames) {
- Worklist[Triple] = *Output;
- ++Output;
- }
-
- // Read all the bundles that are in the work list. If we find no bundles we
- // assume the file is meant for the host target.
- bool FoundHostBundle = false;
- while (!Worklist.empty()) {
- Expected<Optional<StringRef>> CurTripleOrErr = FH->ReadBundleStart(Input);
- if (!CurTripleOrErr)
- return CurTripleOrErr.takeError();
-
- // We don't have more bundles.
- if (!*CurTripleOrErr)
- break;
-
- StringRef CurTriple = **CurTripleOrErr;
- assert(!CurTriple.empty());
-
- auto Output = Worklist.find(CurTriple);
- // The file may have more bundles for other targets, that we don't care
- // about. Therefore, move on to the next triple
- if (Output == Worklist.end())
- continue;
-
- // Check if the output file can be opened and copy the bundle to it.
- std::error_code EC;
- raw_fd_ostream OutputFile(Output->second, EC, sys::fs::OF_None);
- if (EC)
- return createFileError(Output->second, EC);
- if (Error Err = FH->ReadBundle(OutputFile, Input))
- return Err;
- if (Error Err = FH->ReadBundleEnd(Input))
- return Err;
- Worklist.erase(Output);
-
- // Record if we found the host bundle.
- auto OffloadInfo = OffloadTargetInfo(CurTriple);
- if (OffloadInfo.hasHostKind())
- FoundHostBundle = true;
- }
-
- if (!AllowMissingBundles && !Worklist.empty()) {
- std::string ErrMsg = "Can't find bundles for";
- std::set<StringRef> Sorted;
- for (auto &E : Worklist)
- Sorted.insert(E.first());
- unsigned I = 0;
- unsigned Last = Sorted.size() - 1;
- for (auto &E : Sorted) {
- if (I != 0 && Last > 1)
- ErrMsg += ",";
- ErrMsg += " ";
- if (I == Last && I != 0)
- ErrMsg += "and ";
- ErrMsg += E.str();
- ++I;
- }
- return createStringError(inconvertibleErrorCode(), ErrMsg);
- }
-
- // If no bundles were found, assume the input file is the host bundle and
- // create empty files for the remaining targets.
- if (Worklist.size() == TargetNames.size()) {
- for (auto &E : Worklist) {
- std::error_code EC;
- raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
- if (EC)
- return createFileError(E.second, EC);
-
- // If this entry has a host kind, copy the input file to the output file.
- auto OffloadInfo = OffloadTargetInfo(E.getKey());
- if (OffloadInfo.hasHostKind())
- OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
- }
- return Error::success();
- }
-
- // If we found elements, we emit an error if none of those were for the host
- // in case host bundle name was provided in command line.
- if (!FoundHostBundle && HostInputIndex != ~0u)
- return createStringError(inconvertibleErrorCode(),
- "Can't find bundle for the host target");
-
- // If we still have any elements in the worklist, create empty files for them.
- for (auto &E : Worklist) {
- std::error_code EC;
- raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
- if (EC)
- return createFileError(E.second, EC);
- }
-
- return Error::success();
-}
-
-static Archive::Kind getDefaultArchiveKindForHost() {
- return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
- : Archive::K_GNU;
-}
-
-/// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
-/// target \p TargetInfo.
-/// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
-bool isCodeObjectCompatible(OffloadTargetInfo &CodeObjectInfo,
- OffloadTargetInfo &TargetInfo) {
-
- // Compatible in case of exact match.
- if (CodeObjectInfo == TargetInfo) {
- DEBUG_WITH_TYPE(
- "CodeObjectCompatibility",
- dbgs() << "Compatible: Exact match: " << CodeObjectInfo.str() << "\n");
- return true;
- }
-
- // Incompatible if Kinds or Triples mismatch.
- if (CodeObjectInfo.OffloadKind != TargetInfo.OffloadKind ||
- !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
- DEBUG_WITH_TYPE(
- "CodeObjectCompatibility",
- dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
- << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
- << "]\n");
- return false;
- }
-
- // Incompatible if GPUArch mismatch.
- if (CodeObjectInfo.GPUArch != TargetInfo.GPUArch) {
- DEBUG_WITH_TYPE("CodeObjectCompatibility",
- dbgs() << "Incompatible: GPU Arch mismatch \t[CodeObject: "
- << CodeObjectInfo.str()
- << "]\t:\t[Target: " << TargetInfo.str() << "]\n");
- return false;
- }
-
- DEBUG_WITH_TYPE(
- "CodeObjectCompatibility",
- dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
- << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
- << "]\n");
- return true;
-}
-
-/// @brief Computes a list of targets among all given targets which are
-/// compatible with this code object
-/// @param [in] Code Object \p CodeObject
-/// @param [out] List of all compatible targets \p CompatibleTargets among all
-/// given targets
-/// @return false, if no compatible target is found.
-static bool
-getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo,
- SmallVectorImpl<StringRef> &CompatibleTargets) {
- if (!CompatibleTargets.empty()) {
- DEBUG_WITH_TYPE("CodeObjectCompatibility",
- dbgs() << "CompatibleTargets list should be empty\n");
- return false;
- }
- for (auto &Target : TargetNames) {
- auto TargetInfo = OffloadTargetInfo(Target);
- if (isCodeObjectCompatible(CodeObjectInfo, TargetInfo))
- CompatibleTargets.push_back(Target);
- }
- return !CompatibleTargets.empty();
-}
-
-/// UnbundleArchive takes an archive file (".a") as input containing bundled
-/// code object files, and a list of offload targets (not host), and extracts
-/// the code objects into a new archive file for each offload target. Each
-/// resulting archive file contains all code object files corresponding to that
-/// particular offload target. The created archive file does not
-/// contain an index of the symbols and code object files are named as
-/// <<Parent Bundle Name>-<CodeObject's GPUArch>>, with ':' replaced with '_'.
-static Error UnbundleArchive() {
- std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
-
- /// Map of target names with list of object files that will form the device
- /// specific archive for that target
- StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
-
- // Map of target names and output archive filenames
- StringMap<StringRef> TargetOutputFileNameMap;
-
- auto Output = OutputFileNames.begin();
- for (auto &Target : TargetNames) {
- TargetOutputFileNameMap[Target] = *Output;
- ++Output;
- }
-
- StringRef IFName = InputFileNames.front();
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFileOrSTDIN(IFName, true, false);
- if (std::error_code EC = BufOrErr.getError())
- return createFileError(InputFileNames.front(), EC);
-
- ArchiveBuffers.push_back(std::move(*BufOrErr));
- Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr =
- Archive::create(ArchiveBuffers.back()->getMemBufferRef());
- if (!LibOrErr)
- return LibOrErr.takeError();
-
- auto Archive = std::move(*LibOrErr);
-
- Error ArchiveErr = Error::success();
- auto ChildEnd = Archive->child_end();
-
- /// Iterate over all bundled code object files in the input archive.
- for (auto ArchiveIter = Archive->child_begin(ArchiveErr);
- ArchiveIter != ChildEnd; ++ArchiveIter) {
- if (ArchiveErr)
- return ArchiveErr;
- auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
- if (!ArchiveChildNameOrErr)
- return ArchiveChildNameOrErr.takeError();
-
- StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
-
- auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
- if (!CodeObjectBufferRefOrErr)
- return CodeObjectBufferRefOrErr.takeError();
-
- auto CodeObjectBuffer =
- MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false);
-
- Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
- CreateFileHandler(*CodeObjectBuffer);
- if (!FileHandlerOrErr)
- return FileHandlerOrErr.takeError();
-
- std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
- assert(FileHandler &&
- "FileHandle creation failed for file in the archive!");
-
- if (Error ReadErr = FileHandler.get()->ReadHeader(*CodeObjectBuffer))
- return ReadErr;
-
- Expected<Optional<StringRef>> CurBundleIDOrErr =
- FileHandler->ReadBundleStart(*CodeObjectBuffer);
- if (!CurBundleIDOrErr)
- return CurBundleIDOrErr.takeError();
-
- Optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
- // No device code in this child, skip.
- if (!OptionalCurBundleID.hasValue())
- continue;
- StringRef CodeObject = *OptionalCurBundleID;
-
- // Process all bundle entries (CodeObjects) found in this child of input
- // archive.
- while (!CodeObject.empty()) {
- SmallVector<StringRef> CompatibleTargets;
- auto CodeObjectInfo = OffloadTargetInfo(CodeObject);
- if (CodeObjectInfo.hasHostKind()) {
- // Do nothing, we don't extract host code yet.
- } else if (getCompatibleOffloadTargets(CodeObjectInfo,
- CompatibleTargets)) {
- std::string BundleData;
- raw_string_ostream DataStream(BundleData);
- if (Error Err =
- FileHandler.get()->ReadBundle(DataStream, *CodeObjectBuffer))
- return Err;
-
- for (auto &CompatibleTarget : CompatibleTargets) {
- SmallString<128> BundledObjectFileName;
- BundledObjectFileName.assign(BundledObjectFile);
- auto OutputBundleName =
- Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" +
- CodeObject)
- .str();
- // Replace ':' in optional target feature list with '_' to ensure
- // cross-platform validity.
- std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':',
- '_');
-
- std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
- DataStream.str(), OutputBundleName);
- ArchiveBuffers.push_back(std::move(MemBuf));
- llvm::MemoryBufferRef MemBufRef =
- MemoryBufferRef(*(ArchiveBuffers.back()));
-
- // For inserting <CompatibleTarget, list<CodeObject>> entry in
- // OutputArchivesMap.
- if (OutputArchivesMap.find(CompatibleTarget) ==
- OutputArchivesMap.end()) {
-
- std::vector<NewArchiveMember> ArchiveMembers;
- ArchiveMembers.push_back(NewArchiveMember(MemBufRef));
- OutputArchivesMap.insert_or_assign(CompatibleTarget,
- std::move(ArchiveMembers));
- } else {
- OutputArchivesMap[CompatibleTarget].push_back(
- NewArchiveMember(MemBufRef));
- }
- }
- }
-
- if (Error Err = FileHandler.get()->ReadBundleEnd(*CodeObjectBuffer))
- return Err;
-
- Expected<Optional<StringRef>> NextTripleOrErr =
- FileHandler->ReadBundleStart(*CodeObjectBuffer);
- if (!NextTripleOrErr)
- return NextTripleOrErr.takeError();
-
- CodeObject = ((*NextTripleOrErr).hasValue()) ? **NextTripleOrErr : "";
- } // End of processing of all bundle entries of this child of input archive.
- } // End of while over children of input archive.
-
- assert(!ArchiveErr && "Error occured while reading archive!");
-
- /// Write out an archive for each target
- for (auto &Target : TargetNames) {
- StringRef FileName = TargetOutputFileNameMap[Target];
- StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
- OutputArchivesMap.find(Target);
- if (CurArchiveMembers != OutputArchivesMap.end()) {
- if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(),
- true, getDefaultArchiveKindForHost(),
- true, false, nullptr))
- return WriteErr;
- } else if (!AllowMissingBundles) {
- std::string ErrMsg =
- Twine("no compatible code object found for the target '" + Target +
- "' in heterogenous archive library: " + IFName)
- .str();
- return createStringError(inconvertibleErrorCode(), ErrMsg);
- }
- }
-
- return Error::success();
-}
-
-static void PrintVersion(raw_ostream &OS) {
- OS << clang::getClangToolFullVersion("clang-offload-bundler") << '\n';
-}
-
-int main(int argc, const char **argv) {
+ // Process commandline options and report errors
sys::PrintStackTraceOnErrorSignal(argv[0]);
cl::HideUnrelatedOptions(ClangOffloadBundlerCategory);
@@ -1306,24 +154,92 @@ int main(int argc, const char **argv) {
return 0;
}
+ /// Class to store bundler options in standard (non-cl::opt) data structures
+ // Avoid using cl::opt variables after these assignments when possible
+ OffloadBundlerConfig BundlerConfig;
+ BundlerConfig.AllowMissingBundles = AllowMissingBundles;
+ BundlerConfig.PrintExternalCommands = PrintExternalCommands;
+ BundlerConfig.HipOpenmpCompatible = HipOpenmpCompatible;
+ BundlerConfig.BundleAlignment = BundleAlignment;
+ BundlerConfig.FilesType = FilesType;
+ BundlerConfig.ObjcopyPath = "";
+
+ BundlerConfig.TargetNames = TargetNames;
+ BundlerConfig.InputFileNames = InputFileNames;
+ BundlerConfig.OutputFileNames = OutputFileNames;
+
+ /// The index of the host input in the list of inputs.
+ BundlerConfig.HostInputIndex = ~0u;
+
+ /// Whether not having host target is allowed.
+ BundlerConfig.AllowNoHost = false;
+
auto reportError = [argv](Error E) {
logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
exit(1);
};
auto doWork = [&](std::function<llvm::Error()> Work) {
- // Save the current executable directory as it will be useful to find other
- // tools.
- BundlerExecutable = argv[0];
- if (!llvm::sys::fs::exists(BundlerExecutable))
- BundlerExecutable =
- sys::fs::getMainExecutable(argv[0], &BundlerExecutable);
-
if (llvm::Error Err = Work()) {
reportError(std::move(Err));
}
};
+ auto warningOS = [argv]() -> raw_ostream & {
+ return WithColor::warning(errs(), StringRef(argv[0]));
+ };
+
+ /// Path to the current binary.
+ std::string BundlerExecutable = argv[0];
+
+ if (!llvm::sys::fs::exists(BundlerExecutable))
+ BundlerExecutable =
+ sys::fs::getMainExecutable(argv[0], &BundlerExecutable);
+
+ // Find llvm-objcopy in order to create the bundle binary.
+ ErrorOr<std::string> Objcopy = sys::findProgramByName(
+ "llvm-objcopy",
+ sys::path::parent_path(BundlerExecutable));
+ if (!Objcopy)
+ Objcopy = sys::findProgramByName("llvm-objcopy");
+ if (!Objcopy)
+ reportError(createStringError(Objcopy.getError(),
+ "unable to find 'llvm-objcopy' in path"));
+ else
+ BundlerConfig.ObjcopyPath = *Objcopy;
+
+ if (InputFileNames.getNumOccurrences() != 0 &&
+ InputFileNamesDeprecatedOpt.getNumOccurrences() != 0) {
+ reportError(createStringError(
+ errc::invalid_argument,
+ "-inputs and -input cannot be used together, use only -input instead"));
+ }
+
+ if (InputFileNamesDeprecatedOpt.size()) {
+ warningOS() << "-inputs is deprecated, use -input instead\n";
+ // temporary hack to support -inputs
+ std::vector<std::string> &s = InputFileNames;
+ s.insert(s.end(), InputFileNamesDeprecatedOpt.begin(),
+ InputFileNamesDeprecatedOpt.end());
+ }
+ BundlerConfig.InputFileNames = InputFileNames;
+
+ if (OutputFileNames.getNumOccurrences() != 0 &&
+ OutputFileNamesDeprecatedOpt.getNumOccurrences() != 0) {
+ reportError(createStringError(errc::invalid_argument,
+ "-outputs and -output cannot be used "
+ "together, use only -output instead"));
+ }
+
+ if (OutputFileNamesDeprecatedOpt.size()) {
+ warningOS() << "-outputs is deprecated, use -output instead\n";
+ // temporary hack to support -outputs
+ std::vector<std::string> &s = OutputFileNames;
+ s.insert(s.end(), OutputFileNamesDeprecatedOpt.begin(),
+ OutputFileNamesDeprecatedOpt.end());
+ }
+ BundlerConfig.OutputFileNames = OutputFileNames;
+
if (ListBundleIDs) {
if (Unbundle) {
reportError(
@@ -1343,20 +259,23 @@ int main(int argc, const char **argv) {
"-targets option is invalid for -list"));
}
- doWork([]() { return ListBundleIDsInFile(InputFileNames.front()); });
+ doWork([&]() { return OffloadBundler::ListBundleIDsInFile(
+ InputFileNames.front(),
+ BundlerConfig); });
return 0;
}
- if (OutputFileNames.getNumOccurrences() == 0) {
- reportError(createStringError(
- errc::invalid_argument,
- "for the --outputs option: must be specified at least once!"));
+ if (OutputFileNames.size() == 0) {
+ reportError(
+ createStringError(errc::invalid_argument, "no output file specified!"));
}
+
if (TargetNames.getNumOccurrences() == 0) {
reportError(createStringError(
errc::invalid_argument,
"for the --targets option: must be specified at least once!"));
}
+
if (Unbundle) {
if (InputFileNames.size() != 1) {
reportError(createStringError(
@@ -1369,7 +288,7 @@ int main(int argc, const char **argv) {
"match in unbundling mode"));
}
} else {
- if (FilesType == "a") {
+ if (BundlerConfig.FilesType == "a") {
reportError(createStringError(errc::invalid_argument,
"Archive files are only supported "
"for unbundling"));
@@ -1392,6 +311,8 @@ int main(int argc, const char **argv) {
unsigned HostTargetNum = 0u;
bool HIPOnly = true;
llvm::DenseSet<StringRef> ParsedTargets;
+ // Map {offload-kind}-{triple} to target IDs.
+ std::map<std::string, std::set<StringRef>> TargetIDs;
for (StringRef Target : TargetNames) {
if (ParsedTargets.contains(Target)) {
reportError(createStringError(errc::invalid_argument,
@@ -1399,7 +320,7 @@ int main(int argc, const char **argv) {
}
ParsedTargets.insert(Target);
- auto OffloadInfo = OffloadTargetInfo(Target);
+ auto OffloadInfo = OffloadTargetInfo(Target, BundlerConfig);
bool KindIsValid = OffloadInfo.isOffloadKindValid();
bool TripleIsValid = OffloadInfo.isTripleValid();
@@ -1414,10 +335,12 @@ int main(int argc, const char **argv) {
reportError(createStringError(errc::invalid_argument, Msg.str()));
}
+ TargetIDs[OffloadInfo.OffloadKind.str() + "-" + OffloadInfo.Triple.str()]
+ .insert(OffloadInfo.TargetID);
if (KindIsValid && OffloadInfo.hasHostKind()) {
++HostTargetNum;
// Save the index of the input that refers to the host.
- HostInputIndex = Index;
+ BundlerConfig.HostInputIndex = Index;
}
if (OffloadInfo.OffloadKind != "hip" && OffloadInfo.OffloadKind != "hipv4")
@@ -1425,29 +348,42 @@ int main(int argc, const char **argv) {
++Index;
}
+ for (const auto &TargetID : TargetIDs) {
+ if (auto ConflictingTID =
+ clang::getConflictTargetIDCombination(TargetID.second)) {
+ SmallVector<char, 128u> Buf;
+ raw_svector_ostream Msg(Buf);
+ Msg << "Cannot bundle inputs with conflicting targets: '"
+ << TargetID.first + "-" + ConflictingTID->first << "' and '"
+ << TargetID.first + "-" + ConflictingTID->second << "'";
+ reportError(createStringError(errc::invalid_argument, Msg.str()));
+ }
+ }
// HIP uses clang-offload-bundler to bundle device-only compilation results
// for multiple GPU archs, therefore allow no host target if all entries
// are for HIP.
- AllowNoHost = HIPOnly;
+ BundlerConfig.AllowNoHost = HIPOnly;
// Host triple is not really needed for unbundling operation, so do not
// treat missing host triple as error if we do unbundling.
if ((Unbundle && HostTargetNum > 1) ||
- (!Unbundle && HostTargetNum != 1 && !AllowNoHost)) {
+ (!Unbundle && HostTargetNum != 1 && !BundlerConfig.AllowNoHost)) {
reportError(createStringError(errc::invalid_argument,
"expecting exactly one host target but got " +
Twine(HostTargetNum)));
}
- doWork([]() {
+ OffloadBundler Bundler(BundlerConfig);
+
+ doWork([&]() {
if (Unbundle) {
- if (FilesType == "a")
- return UnbundleArchive();
+ if (BundlerConfig.FilesType == "a")
+ return Bundler.UnbundleArchive();
else
- return UnbundleFiles();
+ return Bundler.UnbundleFiles();
} else
- return BundleFiles();
+ return Bundler.BundleFiles();
});
return 0;
}
diff --git a/gnu/llvm/clang/tools/clang-offload-packager/CMakeLists.txt b/gnu/llvm/clang/tools/clang-offload-packager/CMakeLists.txt
new file mode 100644
index 00000000000..accc9486f46
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-offload-packager/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ BinaryFormat
+ Object
+ Support)
+
+add_clang_tool(clang-offload-packager
+ ClangOffloadPackager.cpp
+
+ DEPENDS
+ ${tablegen_deps}
+ )
+
+add_dependencies(clang clang-offload-packager)
+
+clang_target_link_libraries(clang-offload-packager
+ PRIVATE
+ clangBasic
+ )
diff --git a/gnu/llvm/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp b/gnu/llvm/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp
new file mode 100644
index 00000000000..47ef155ef27
--- /dev/null
+++ b/gnu/llvm/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp
@@ -0,0 +1,221 @@
+//===-- clang-offload-packager/ClangOffloadPackager.cpp - file bundler ---===//
+//
+// 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 tool takes several device object files and bundles them into a single
+// binary image using a custom binary format. This is intended to be used to
+// embed many device files into an application to create a fat binary.
+//
+//===---------------------------------------------------------------------===//
+
+#include "clang/Basic/Version.h"
+
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/OffloadBinary.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/WithColor.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+
+static cl::OptionCategory
+ ClangOffloadPackagerCategory("clang-offload-packager options");
+
+static cl::opt<std::string> OutputFile("o", cl::desc("Write output to <file>."),
+ cl::value_desc("file"),
+ cl::cat(ClangOffloadPackagerCategory));
+
+static cl::opt<std::string> InputFile(cl::Positional,
+ cl::desc("Extract from <file>."),
+ cl::value_desc("file"),
+ cl::cat(ClangOffloadPackagerCategory));
+
+static cl::list<std::string>
+ DeviceImages("image",
+ cl::desc("List of key and value arguments. Required keywords "
+ "are 'file' and 'triple'."),
+ cl::value_desc("<key>=<value>,..."),
+ cl::cat(ClangOffloadPackagerCategory));
+
+static void PrintVersion(raw_ostream &OS) {
+ OS << clang::getClangToolFullVersion("clang-offload-packager") << '\n';
+}
+
+// Get a map containing all the arguments for the image. Repeated arguments will
+// be placed in a comma separated list.
+static DenseMap<StringRef, StringRef> getImageArguments(StringRef Image,
+ StringSaver &Saver) {
+ DenseMap<StringRef, StringRef> Args;
+ for (StringRef Arg : llvm::split(Image, ",")) {
+ auto [Key, Value] = Arg.split("=");
+ if (Args.count(Key))
+ Args[Key] = Saver.save(Args[Key] + "," + Value);
+ else
+ Args[Key] = Value;
+ }
+
+ return Args;
+}
+
+static Error bundleImages() {
+ SmallVector<char, 1024> BinaryData;
+ raw_svector_ostream OS(BinaryData);
+ for (StringRef Image : DeviceImages) {
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+ DenseMap<StringRef, StringRef> Args = getImageArguments(Image, Saver);
+
+ if (!Args.count("triple") || !Args.count("file"))
+ return createStringError(
+ inconvertibleErrorCode(),
+ "'file' and 'triple' are required image arguments");
+
+ OffloadBinary::OffloadingImage ImageBinary{};
+ std::unique_ptr<llvm::MemoryBuffer> DeviceImage;
+ for (const auto &[Key, Value] : Args) {
+ if (Key == "file") {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ObjectOrErr =
+ llvm::MemoryBuffer::getFileOrSTDIN(Value);
+ if (std::error_code EC = ObjectOrErr.getError())
+ return errorCodeToError(EC);
+
+ // Clang uses the '.o' suffix for LTO bitcode.
+ if (identify_magic((*ObjectOrErr)->getBuffer()) == file_magic::bitcode)
+ ImageBinary.TheImageKind = object::IMG_Bitcode;
+ else
+ ImageBinary.TheImageKind =
+ getImageKind(sys::path::extension(Value).drop_front());
+ ImageBinary.Image = std::move(*ObjectOrErr);
+ } else if (Key == "kind") {
+ ImageBinary.TheOffloadKind = getOffloadKind(Value);
+ } else {
+ ImageBinary.StringData[Key] = Value;
+ }
+ }
+ std::unique_ptr<MemoryBuffer> Buffer = OffloadBinary::write(ImageBinary);
+ if (Buffer->getBufferSize() % OffloadBinary::getAlignment() != 0)
+ return createStringError(inconvertibleErrorCode(),
+ "Offload binary has invalid size alignment");
+ OS << Buffer->getBuffer();
+ }
+
+ Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
+ FileOutputBuffer::create(OutputFile, BinaryData.size());
+ if (!OutputOrErr)
+ return OutputOrErr.takeError();
+ std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
+ std::copy(BinaryData.begin(), BinaryData.end(), Output->getBufferStart());
+ if (Error E = Output->commit())
+ return E;
+ return Error::success();
+}
+
+static Error unbundleImages() {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+ MemoryBuffer::getFileOrSTDIN(InputFile);
+ if (std::error_code EC = BufferOrErr.getError())
+ return createFileError(InputFile, EC);
+ std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrErr);
+
+ // This data can be misaligned if extracted from an archive.
+ if (!isAddrAligned(Align(OffloadBinary::getAlignment()),
+ Buffer->getBufferStart()))
+ Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(),
+ Buffer->getBufferIdentifier());
+
+ SmallVector<OffloadFile> Binaries;
+ if (Error Err = extractOffloadBinaries(*Buffer, Binaries))
+ return Err;
+
+ // Try to extract each device image specified by the user from the input file.
+ for (StringRef Image : DeviceImages) {
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+ auto Args = getImageArguments(Image, Saver);
+
+ for (uint64_t I = 0, E = Binaries.size(); I != E; ++I) {
+ const auto *Binary = Binaries[I].getBinary();
+ // We handle the 'file' and 'kind' identifiers differently.
+ bool Match = llvm::all_of(Args, [&](auto &Arg) {
+ const auto [Key, Value] = Arg;
+ if (Key == "file")
+ return true;
+ if (Key == "kind")
+ return Binary->getOffloadKind() == getOffloadKind(Value);
+ return Binary->getString(Key) == Value;
+ });
+ if (!Match)
+ continue;
+
+ // If the user did not provide a filename derive one from the input and
+ // image.
+ StringRef Filename =
+ !Args.count("file")
+ ? Saver.save(sys::path::stem(InputFile) + "-" +
+ Binary->getTriple() + "-" + Binary->getArch() + "." +
+ std::to_string(I) + "." +
+ getImageKindName(Binary->getImageKind()))
+ : Args["file"];
+
+ Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
+ FileOutputBuffer::create(Filename, Binary->getImage().size());
+ if (!OutputOrErr)
+ return OutputOrErr.takeError();
+ std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
+ llvm::copy(Binary->getImage(), Output->getBufferStart());
+ if (Error E = Output->commit())
+ return E;
+ }
+ }
+
+ return Error::success();
+}
+
+int main(int argc, const char **argv) {
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+ cl::HideUnrelatedOptions(ClangOffloadPackagerCategory);
+ cl::SetVersionPrinter(PrintVersion);
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "A utility for bundling several object files into a single binary.\n"
+ "The output binary can then be embedded into the host section table\n"
+ "to create a fatbinary containing offloading code.\n");
+
+ if (Help) {
+ cl::PrintHelpMessage();
+ return EXIT_SUCCESS;
+ }
+
+ auto reportError = [argv](Error E) {
+ logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
+ return EXIT_FAILURE;
+ };
+
+ if (!InputFile.empty() && !OutputFile.empty())
+ return reportError(
+ createStringError(inconvertibleErrorCode(),
+ "Packaging to an output file and extracting from an "
+ "input file are mutually exclusive."));
+
+ if (!OutputFile.empty()) {
+ if (Error Err = bundleImages())
+ return reportError(std::move(Err));
+ } else if (!InputFile.empty()) {
+ if (Error Err = unbundleImages())
+ return reportError(std::move(Err));
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/gnu/llvm/clang/tools/clang-refactor/ClangRefactor.cpp b/gnu/llvm/clang/tools/clang-refactor/ClangRefactor.cpp
index eacd00a601d..d362eecf06d 100644
--- a/gnu/llvm/clang/tools/clang-refactor/ClangRefactor.cpp
+++ b/gnu/llvm/clang/tools/clang-refactor/ClangRefactor.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
#include <string>
using namespace clang;
@@ -39,11 +40,11 @@ static cl::OptionCategory CommonRefactorOptions("Refactoring options");
static cl::opt<bool> Verbose("v", cl::desc("Use verbose output"),
cl::cat(cl::getGeneralCategory()),
- cl::sub(*cl::AllSubCommands));
+ cl::sub(cl::SubCommand::getAll()));
static cl::opt<bool> Inplace("i", cl::desc("Inplace edit <file>s"),
cl::cat(cl::getGeneralCategory()),
- cl::sub(*cl::AllSubCommands));
+ cl::sub(cl::SubCommand::getAll()));
} // end namespace opts
@@ -147,14 +148,14 @@ std::unique_ptr<SourceSelectionArgument>
SourceSelectionArgument::fromString(StringRef Value) {
if (Value.startswith("test:")) {
StringRef Filename = Value.drop_front(strlen("test:"));
- Optional<TestSelectionRangesInFile> ParsedTestSelection =
+ std::optional<TestSelectionRangesInFile> ParsedTestSelection =
findTestSelectionRanges(Filename);
if (!ParsedTestSelection)
return nullptr; // A parsing error was already reported.
return std::make_unique<TestSourceSelectionArgument>(
std::move(*ParsedTestSelection));
}
- Optional<ParsedSourceRange> Range = ParsedSourceRange::fromString(Value);
+ std::optional<ParsedSourceRange> Range = ParsedSourceRange::fromString(Value);
if (Range)
return std::make_unique<SourceRangeSelectionArgument>(std::move(*Range));
llvm::errs() << "error: '-selection' option must be specified using "
@@ -194,13 +195,13 @@ public:
: Options(Options) {}
void visit(const RefactoringOption &Opt,
- Optional<std::string> &Value) override {
+ std::optional<std::string> &Value) override {
const cl::opt<std::string> &CLOpt = Options.getStringOption(Opt);
if (!CLOpt.getValue().empty()) {
Value = CLOpt.getValue();
return;
}
- Value = None;
+ Value = std::nullopt;
if (Opt.isRequired())
MissingRequiredOptions.push_back(&Opt);
}
@@ -224,7 +225,8 @@ public:
RefactoringActionCommandLineOptions &Options)
: Category(Category), Subcommand(Subcommand), Options(Options) {}
- void visit(const RefactoringOption &Opt, Optional<std::string> &) override {
+ void visit(const RefactoringOption &Opt,
+ std::optional<std::string> &) override {
if (Visited.insert(&Opt).second)
Options.addStringOption(Opt, create<std::string>(Opt));
}
@@ -316,7 +318,7 @@ public:
ClangRefactorConsumer(AtomicChanges &Changes) : SourceChanges(&Changes) {}
void handleError(llvm::Error Err) override {
- Optional<PartialDiagnosticAt> Diag = DiagnosticError::take(Err);
+ std::optional<PartialDiagnosticAt> Diag = DiagnosticError::take(Err);
if (!Diag) {
llvm::errs() << llvm::toString(std::move(Err)) << "\n";
return;
diff --git a/gnu/llvm/clang/tools/clang-refactor/TestSupport.cpp b/gnu/llvm/clang/tools/clang-refactor/TestSupport.cpp
index eb880889749..400313eeab5 100644
--- a/gnu/llvm/clang/tools/clang-refactor/TestSupport.cpp
+++ b/gnu/llvm/clang/tools/clang-refactor/TestSupport.cpp
@@ -24,6 +24,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace llvm;
@@ -177,8 +178,8 @@ bool TestRefactoringResultConsumer::handleAllResults() {
bool Failed = false;
for (auto &Group : llvm::enumerate(Results)) {
// All ranges in the group must produce the same result.
- Optional<tooling::AtomicChanges> CanonicalResult;
- Optional<std::string> CanonicalErrorMessage;
+ std::optional<tooling::AtomicChanges> CanonicalResult;
+ std::optional<std::string> CanonicalErrorMessage;
for (auto &I : llvm::enumerate(Group.value())) {
Expected<tooling::AtomicChanges> &Result = I.value();
std::string ErrorMessage;
@@ -291,14 +292,14 @@ static unsigned addEndLineOffsetAndEndColumn(StringRef Source, unsigned Offset,
Source, LineStart == StringRef::npos ? 0 : LineStart + 1, Column - 1);
}
-Optional<TestSelectionRangesInFile>
+std::optional<TestSelectionRangesInFile>
findTestSelectionRanges(StringRef Filename) {
ErrorOr<std::unique_ptr<MemoryBuffer>> ErrOrFile =
MemoryBuffer::getFile(Filename);
if (!ErrOrFile) {
llvm::errs() << "error: -selection=test:" << Filename
<< " : could not open the given file";
- return None;
+ return std::nullopt;
}
StringRef Source = ErrOrFile.get()->getBuffer();
@@ -340,7 +341,7 @@ findTestSelectionRanges(StringRef Filename) {
// Allow CHECK: comments to contain range= commands.
if (!RangeRegex.match(Comment, &Matches) || Comment.contains("CHECK")) {
if (DetectMistypedCommand())
- return None;
+ return std::nullopt;
continue;
}
unsigned Offset = Tok.getEndLoc().getRawEncoding();
@@ -359,7 +360,7 @@ findTestSelectionRanges(StringRef Filename) {
SmallVector<StringRef, 4> EndLocMatches;
if (!EndLocRegex.match(Matches[3], &EndLocMatches)) {
if (DetectMistypedCommand())
- return None;
+ return std::nullopt;
continue;
}
unsigned EndLineOffset = 0, EndColumn = 0;
@@ -380,7 +381,7 @@ findTestSelectionRanges(StringRef Filename) {
if (GroupedRanges.empty()) {
llvm::errs() << "error: -selection=test:" << Filename
<< ": no 'range' commands";
- return None;
+ return std::nullopt;
}
TestSelectionRangesInFile TestRanges = {Filename.str(), {}};
diff --git a/gnu/llvm/clang/tools/clang-refactor/TestSupport.h b/gnu/llvm/clang/tools/clang-refactor/TestSupport.h
index 1282c3a90f3..4eac9022baa 100644
--- a/gnu/llvm/clang/tools/clang-refactor/TestSupport.h
+++ b/gnu/llvm/clang/tools/clang-refactor/TestSupport.h
@@ -18,10 +18,10 @@
#include "ToolRefactoringResultConsumer.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h"
#include <map>
+#include <optional>
#include <string>
namespace clang {
@@ -93,9 +93,10 @@ struct TestSelectionRangesInFile {
/// because clang-refactor should return zero on exit when the group results are
/// consistent.
///
-/// \returns None on failure (errors are emitted to stderr), or a set of
+/// \returns std::nullopt on failure (errors are emitted to stderr), or a set of
/// grouped source ranges in the given file otherwise.
-Optional<TestSelectionRangesInFile> findTestSelectionRanges(StringRef Filename);
+std::optional<TestSelectionRangesInFile>
+findTestSelectionRanges(StringRef Filename);
} // end namespace refactor
} // end namespace clang
diff --git a/gnu/llvm/clang/tools/clang-rename/CMakeLists.txt b/gnu/llvm/clang/tools/clang-rename/CMakeLists.txt
index cda8e29ec5b..f4c4e520520 100644
--- a/gnu/llvm/clang/tools/clang-rename/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-rename/CMakeLists.txt
@@ -18,9 +18,9 @@ clang_target_link_libraries(clang-rename
clangToolingRefactoring
)
-install(PROGRAMS clang-rename.py
- DESTINATION share/clang
+install(FILES clang-rename.py
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-rename)
-install(PROGRAMS clang-rename.el
- DESTINATION share/clang
+install(FILES clang-rename.el
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-rename)
diff --git a/gnu/llvm/clang/tools/clang-rename/ClangRename.cpp b/gnu/llvm/clang/tools/clang-rename/ClangRename.cpp
index 141ba379ed0..e7ceac7dbf3 100644
--- a/gnu/llvm/clang/tools/clang-rename/ClangRename.cpp
+++ b/gnu/llvm/clang/tools/clang-rename/ClangRename.cpp
@@ -68,17 +68,17 @@ static cl::OptionCategory ClangRenameOptions("clang-rename common options");
static cl::list<unsigned> SymbolOffsets(
"offset",
cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
- cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+ cl::cat(ClangRenameOptions));
static cl::opt<bool> Inplace("i", cl::desc("Overwrite edited <file>s."),
cl::cat(ClangRenameOptions));
static cl::list<std::string>
QualifiedNames("qualified-name",
cl::desc("The fully qualified name of the symbol."),
- cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+ cl::cat(ClangRenameOptions));
static cl::list<std::string>
NewNames("new-name", cl::desc("The new name to change the symbol to."),
- cl::ZeroOrMore, cl::cat(ClangRenameOptions));
+ cl::cat(ClangRenameOptions));
static cl::opt<bool> PrintName(
"pn",
cl::desc("Print the found symbol's name prior to renaming to stderr."),
diff --git a/gnu/llvm/clang/tools/clang-repl/CMakeLists.txt b/gnu/llvm/clang/tools/clang-repl/CMakeLists.txt
index 060c62aa419..b51a18c10cd 100644
--- a/gnu/llvm/clang/tools/clang-repl/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-repl/CMakeLists.txt
@@ -11,8 +11,14 @@ add_clang_tool(clang-repl
ClangRepl.cpp
)
-clang_target_link_libraries(clang-repl PUBLIC
+clang_target_link_libraries(clang-repl PRIVATE
clangBasic
+ clangFrontend
clangInterpreter
clangTooling
)
+
+# Support plugins.
+if(CLANG_PLUGIN_SUPPORT)
+ export_executable_symbols_for_plugins(clang-repl)
+endif()
diff --git a/gnu/llvm/clang/tools/clang-repl/ClangRepl.cpp b/gnu/llvm/clang/tools/clang-repl/ClangRepl.cpp
index ba6bb11abc8..401a31d3406 100644
--- a/gnu/llvm/clang/tools/clang-repl/ClangRepl.cpp
+++ b/gnu/llvm/clang/tools/clang-repl/ClangRepl.cpp
@@ -21,18 +21,18 @@
#include "llvm/Support/ManagedStatic.h" // llvm_shutdown
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h" // llvm::Initialize*
+#include <optional>
static llvm::cl::list<std::string>
- ClangArgs("Xcc", llvm::cl::ZeroOrMore,
+ ClangArgs("Xcc",
llvm::cl::desc("Argument to pass to the CompilerInvocation"),
llvm::cl::CommaSeparated);
static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit",
llvm::cl::Hidden);
static llvm::cl::list<std::string> OptInputs(llvm::cl::Positional,
- llvm::cl::ZeroOrMore,
llvm::cl::desc("[code to run]"));
-static void LLVMErrorHandler(void *UserData, const std::string &Message,
+static void LLVMErrorHandler(void *UserData, const char *Message,
bool GenCrashDiag) {
auto &Diags = *static_cast<clang::DiagnosticsEngine *>(UserData);
@@ -49,11 +49,30 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message,
exit(GenCrashDiag ? 70 : 1);
}
+// If we are running with -verify a reported has to be returned as unsuccess.
+// This is relevant especially for the test suite.
+static int checkDiagErrors(const clang::CompilerInstance *CI, bool HasError) {
+ unsigned Errs = CI->getDiagnostics().getClient()->getNumErrors();
+ if (CI->getDiagnosticOpts().VerifyDiagnostics) {
+ // If there was an error that came from the verifier we must return 1 as
+ // an exit code for the process. This will make the test fail as expected.
+ clang::DiagnosticConsumer *Client = CI->getDiagnostics().getClient();
+ Client->EndSourceFile();
+ Errs = Client->getNumErrors();
+
+ // The interpreter expects BeginSourceFile/EndSourceFiles to be balanced.
+ Client->BeginSourceFile(CI->getLangOpts(), &CI->getPreprocessor());
+ }
+ return (Errs || HasError) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
llvm::ExitOnError ExitOnErr;
int main(int argc, const char **argv) {
ExitOnErr.setBanner("clang-repl: ");
llvm::cl::ParseCommandLineOptions(argc, argv);
+ llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
std::vector<const char *> ClangArgv(ClangArgs.size());
std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
[](const std::string &s) -> const char * { return s.data(); });
@@ -80,20 +99,35 @@ int main(int argc, const char **argv) {
llvm::install_fatal_error_handler(LLVMErrorHandler,
static_cast<void *>(&CI->getDiagnostics()));
+ // Load any requested plugins.
+ CI->LoadRequestedPlugins();
+
auto Interp = ExitOnErr(clang::Interpreter::create(std::move(CI)));
for (const std::string &input : OptInputs) {
if (auto Err = Interp->ParseAndExecute(input))
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
}
+ bool HasError = false;
+
if (OptInputs.empty()) {
llvm::LineEditor LE("clang-repl");
// FIXME: Add LE.setListCompleter
- while (llvm::Optional<std::string> Line = LE.readLine()) {
- if (*Line == "quit")
+ while (std::optional<std::string> Line = LE.readLine()) {
+ if (*Line == R"(%quit)")
break;
- if (auto Err = Interp->ParseAndExecute(*Line))
+ if (*Line == R"(%undo)") {
+ if (auto Err = Interp->Undo()) {
+ llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
+ HasError = true;
+ }
+ continue;
+ }
+
+ if (auto Err = Interp->ParseAndExecute(*Line)) {
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
+ HasError = true;
+ }
}
}
@@ -102,7 +136,5 @@ int main(int argc, const char **argv) {
// later errors use the default handling behavior instead.
llvm::remove_fatal_error_handler();
- llvm::llvm_shutdown();
-
- return 0;
+ return checkDiagErrors(Interp->getCompilerInstance(), HasError);
}
diff --git a/gnu/llvm/clang/tools/clang-scan-deps/CMakeLists.txt b/gnu/llvm/clang/tools/clang-scan-deps/CMakeLists.txt
index 6aa914f3b25..4db565314c0 100644
--- a/gnu/llvm/clang/tools/clang-scan-deps/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/clang-scan-deps/CMakeLists.txt
@@ -1,6 +1,8 @@
set(LLVM_LINK_COMPONENTS
Core
+ Option
Support
+ TargetParser
)
add_clang_tool(clang-scan-deps
diff --git a/gnu/llvm/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/gnu/llvm/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 74784ebd3b9..9c7d454c9ef 100644
--- a/gnu/llvm/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/gnu/llvm/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
@@ -16,6 +18,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Program.h"
@@ -23,6 +26,7 @@
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/Threading.h"
#include <mutex>
+#include <optional>
#include <thread>
using namespace clang;
@@ -81,7 +85,7 @@ public:
"" /*no-suffix*/, ErrorFile);
llvm::FileRemover OutputRemover(OutputFile.c_str());
llvm::FileRemover ErrorRemover(ErrorFile.c_str());
- llvm::Optional<StringRef> Redirects[] = {
+ std::optional<StringRef> Redirects[] = {
{""}, // Stdin
OutputFile.str(),
ErrorFile.str(),
@@ -116,60 +120,48 @@ static llvm::cl::opt<ScanningMode> ScanMode(
"mode",
llvm::cl::desc("The preprocessing mode used to compute the dependencies"),
llvm::cl::values(
- clEnumValN(ScanningMode::MinimizedSourcePreprocessing,
- "preprocess-minimized-sources",
- "The set of dependencies is computed by preprocessing the "
- "source files that were minimized to only include the "
- "contents that might affect the dependencies"),
+ clEnumValN(ScanningMode::DependencyDirectivesScan,
+ "preprocess-dependency-directives",
+ "The set of dependencies is computed by preprocessing with "
+ "special lexing after scanning the source files to get the "
+ "directives that might affect the dependencies"),
clEnumValN(ScanningMode::CanonicalPreprocessing, "preprocess",
"The set of dependencies is computed by preprocessing the "
- "unmodified source files")),
- llvm::cl::init(ScanningMode::MinimizedSourcePreprocessing),
+ "source files")),
+ llvm::cl::init(ScanningMode::DependencyDirectivesScan),
llvm::cl::cat(DependencyScannerCategory));
static llvm::cl::opt<ScanningOutputFormat> Format(
"format", llvm::cl::desc("The output format for the dependencies"),
- llvm::cl::values(clEnumValN(ScanningOutputFormat::Make, "make",
- "Makefile compatible dep file"),
- clEnumValN(ScanningOutputFormat::Full, "experimental-full",
- "Full dependency graph suitable"
- " for explicitly building modules. This format "
- "is experimental and will change.")),
+ llvm::cl::values(
+ clEnumValN(ScanningOutputFormat::Make, "make",
+ "Makefile compatible dep file"),
+ clEnumValN(ScanningOutputFormat::P1689, "p1689",
+ "Generate standard c++ modules dependency P1689 format"),
+ clEnumValN(ScanningOutputFormat::Full, "experimental-full",
+ "Full dependency graph suitable"
+ " for explicitly building modules. This format "
+ "is experimental and will change.")),
llvm::cl::init(ScanningOutputFormat::Make),
llvm::cl::cat(DependencyScannerCategory));
-// This mode is mostly useful for development of explicitly built modules.
-// Command lines will contain arguments specifying modulemap file paths and
-// absolute paths to PCM files in the module cache directory.
-//
-// Build tools that want to put the PCM files in a different location should use
-// the C++ APIs instead, of which there are two flavors:
-//
-// 1. APIs that generate arguments with paths to modulemap and PCM files via
-// callbacks provided by the client:
-// * ModuleDeps::getCanonicalCommandLine(LookupPCMPath, LookupModuleDeps)
-// * FullDependencies::getAdditionalArgs(LookupPCMPath, LookupModuleDeps)
-//
-// 2. APIs that don't generate arguments with paths to modulemap or PCM files
-// and instead expect the client to append them manually after the fact:
-// * ModuleDeps::getCanonicalCommandLineWithoutModulePaths()
-// * FullDependencies::getAdditionalArgsWithoutModulePaths()
-//
-static llvm::cl::opt<bool> GenerateModulesPathArgs(
- "generate-modules-path-args",
- llvm::cl::desc(
- "With '-format experimental-full', include arguments specifying "
- "modules-related paths in the generated command lines: "
- "'-fmodule-file=', '-o', '-fmodule-map-file='."),
- llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory));
-
static llvm::cl::opt<std::string> ModuleFilesDir(
"module-files-dir",
- llvm::cl::desc("With '-generate-modules-path-args', paths to module files "
- "in the generated command lines will begin with the "
- "specified directory instead the module cache directory."),
+ llvm::cl::desc(
+ "The build directory for modules. Defaults to the value of "
+ "'-fmodules-cache-path=' from command lines for implicit modules."),
llvm::cl::cat(DependencyScannerCategory));
+static llvm::cl::opt<bool> OptimizeArgs(
+ "optimize-args",
+ llvm::cl::desc("Whether to optimize command-line arguments of modules."),
+ llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory));
+
+static llvm::cl::opt<bool> EagerLoadModules(
+ "eager-load-pcm",
+ llvm::cl::desc("Load PCM files eagerly (instead of lazily on import)."),
+ llvm::cl::init(false), llvm::cl::cat(DependencyScannerCategory));
+
llvm::cl::opt<unsigned>
NumThreads("j", llvm::cl::Optional,
llvm::cl::desc("Number of worker threads to use (default: use "
@@ -178,21 +170,47 @@ llvm::cl::opt<unsigned>
llvm::cl::opt<std::string>
CompilationDB("compilation-database",
- llvm::cl::desc("Compilation database"), llvm::cl::Required,
+ llvm::cl::desc("Compilation database"), llvm::cl::Optional,
llvm::cl::cat(DependencyScannerCategory));
-llvm::cl::opt<bool> ReuseFileManager(
- "reuse-filemanager",
- llvm::cl::desc("Reuse the file manager and its cache between invocations."),
- llvm::cl::init(true), llvm::cl::cat(DependencyScannerCategory));
+llvm::cl::opt<std::string> P1689TargettedCommand(
+ llvm::cl::Positional, llvm::cl::ZeroOrMore,
+ llvm::cl::desc("The command line flags for the target of which "
+ "the dependencies are to be computed."));
-llvm::cl::opt<bool> SkipExcludedPPRanges(
- "skip-excluded-pp-ranges",
- llvm::cl::desc(
- "Use the preprocessor optimization that skips excluded conditionals by "
- "bumping the buffer pointer in the lexer instead of lexing the tokens "
- "until reaching the end directive."),
- llvm::cl::init(true), llvm::cl::cat(DependencyScannerCategory));
+llvm::cl::opt<std::string> ModuleName(
+ "module-name", llvm::cl::Optional,
+ llvm::cl::desc("the module of which the dependencies are to be computed"),
+ llvm::cl::cat(DependencyScannerCategory));
+
+llvm::cl::list<std::string> ModuleDepTargets(
+ "dependency-target",
+ llvm::cl::desc("The names of dependency targets for the dependency file"),
+ llvm::cl::cat(DependencyScannerCategory));
+
+llvm::cl::opt<bool> DeprecatedDriverCommand(
+ "deprecated-driver-command", llvm::cl::Optional,
+ llvm::cl::desc("use a single driver command to build the tu (deprecated)"),
+ llvm::cl::cat(DependencyScannerCategory));
+
+enum ResourceDirRecipeKind {
+ RDRK_ModifyCompilerPath,
+ RDRK_InvokeCompiler,
+};
+
+static llvm::cl::opt<ResourceDirRecipeKind> ResourceDirRecipe(
+ "resource-dir-recipe",
+ llvm::cl::desc("How to produce missing '-resource-dir' argument"),
+ llvm::cl::values(
+ clEnumValN(RDRK_ModifyCompilerPath, "modify-compiler-path",
+ "Construct the resource directory from the compiler path in "
+ "the compilation database. This assumes it's part of the "
+ "same toolchain as this clang-scan-deps. (default)"),
+ clEnumValN(RDRK_InvokeCompiler, "invoke-compiler",
+ "Invoke the compiler with '-print-resource-dir' and use the "
+ "reported path as the resource directory. (deprecated)")),
+ llvm::cl::init(RDRK_ModifyCompilerPath),
+ llvm::cl::cat(DependencyScannerCategory));
llvm::cl::opt<bool> Verbose("v", llvm::cl::Optional,
llvm::cl::desc("Use verbose output."),
@@ -201,24 +219,6 @@ llvm::cl::opt<bool> Verbose("v", llvm::cl::Optional,
} // end anonymous namespace
-class SingleCommandCompilationDatabase : public tooling::CompilationDatabase {
-public:
- SingleCommandCompilationDatabase(tooling::CompileCommand Cmd)
- : Command(std::move(Cmd)) {}
-
- std::vector<tooling::CompileCommand>
- getCompileCommands(StringRef FilePath) const override {
- return {Command};
- }
-
- std::vector<tooling::CompileCommand> getAllCompileCommands() const override {
- return {Command};
- }
-
-private:
- tooling::CompileCommand Command;
-};
-
/// Takes the result of a dependency scan and prints error / dependency files
/// based on the result.
///
@@ -267,7 +267,7 @@ class FullDeps {
public:
void mergeDeps(StringRef Input, FullDependenciesResult FDR,
size_t InputIndex) {
- const FullDependencies &FD = FDR.FullDeps;
+ FullDependencies &FD = FDR.FullDeps;
InputDeps ID;
ID.FileName = std::string(Input);
@@ -285,15 +285,8 @@ public:
Modules.insert(I, {{MD.ID, InputIndex}, std::move(MD)});
}
- ID.AdditionalCommandLine =
- GenerateModulesPathArgs
- ? FD.getAdditionalArgs(
- [&](ModuleID MID) { return lookupPCMPath(MID); },
- [&](ModuleID MID) -> const ModuleDeps & {
- return lookupModuleDeps(MID);
- })
- : FD.getAdditionalArgsWithoutModulePaths();
-
+ ID.DriverCommandLine = std::move(FD.DriverCommandLine);
+ ID.Commands = std::move(FD.Commands);
Inputs.push_back(std::move(ID));
}
@@ -323,28 +316,40 @@ public:
{"file-deps", toJSONSorted(MD.FileDeps)},
{"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)},
{"clang-modulemap-file", MD.ClangModuleMapFile},
- {"command-line",
- GenerateModulesPathArgs
- ? MD.getCanonicalCommandLine(
- [&](ModuleID MID) { return lookupPCMPath(MID); },
- [&](ModuleID MID) -> const ModuleDeps & {
- return lookupModuleDeps(MID);
- })
- : MD.getCanonicalCommandLineWithoutModulePaths()},
+ {"command-line", MD.BuildArguments},
};
OutModules.push_back(std::move(O));
}
Array TUs;
for (auto &&I : Inputs) {
- Object O{
- {"input-file", I.FileName},
- {"clang-context-hash", I.ContextHash},
- {"file-deps", I.FileDeps},
- {"clang-module-deps", toJSONSorted(I.ModuleDeps)},
- {"command-line", I.AdditionalCommandLine},
- };
- TUs.push_back(std::move(O));
+ Array Commands;
+ if (I.DriverCommandLine.empty()) {
+ for (const auto &Cmd : I.Commands) {
+ Object O{
+ {"input-file", I.FileName},
+ {"clang-context-hash", I.ContextHash},
+ {"file-deps", I.FileDeps},
+ {"clang-module-deps", toJSONSorted(I.ModuleDeps)},
+ {"executable", Cmd.Executable},
+ {"command-line", Cmd.Arguments},
+ };
+ Commands.push_back(std::move(O));
+ }
+ } else {
+ Object O{
+ {"input-file", I.FileName},
+ {"clang-context-hash", I.ContextHash},
+ {"file-deps", I.FileDeps},
+ {"clang-module-deps", toJSONSorted(I.ModuleDeps)},
+ {"executable", "clang"},
+ {"command-line", I.DriverCommandLine},
+ };
+ Commands.push_back(std::move(O));
+ }
+ TUs.push_back(Object{
+ {"commands", std::move(Commands)},
+ });
}
Object Output{
@@ -356,31 +361,6 @@ public:
}
private:
- StringRef lookupPCMPath(ModuleID MID) {
- auto PCMPath = PCMPaths.insert({MID, ""});
- if (PCMPath.second)
- PCMPath.first->second = constructPCMPath(lookupModuleDeps(MID));
- return PCMPath.first->second;
- }
-
- /// Construct a path for the explicitly built PCM.
- std::string constructPCMPath(const ModuleDeps &MD) const {
- StringRef Filename = llvm::sys::path::filename(MD.ImplicitModulePCMPath);
-
- SmallString<256> ExplicitPCMPath(
- !ModuleFilesDir.empty()
- ? ModuleFilesDir
- : MD.Invocation.getHeaderSearchOpts().ModuleCachePath);
- llvm::sys::path::append(ExplicitPCMPath, MD.ID.ContextHash, Filename);
- return std::string(ExplicitPCMPath);
- }
-
- const ModuleDeps &lookupModuleDeps(ModuleID MID) {
- auto I = Modules.find(IndexedModuleID{MID, 0});
- assert(I != Modules.end());
- return I->second;
- };
-
struct IndexedModuleID {
ModuleID ID;
mutable size_t InputIndex;
@@ -404,13 +384,13 @@ private:
std::string ContextHash;
std::vector<std::string> FileDeps;
std::vector<ModuleID> ModuleDeps;
- std::vector<std::string> AdditionalCommandLine;
+ std::vector<std::string> DriverCommandLine;
+ std::vector<Command> Commands;
};
std::mutex Lock;
std::unordered_map<IndexedModuleID, ModuleDeps, IndexedModuleIDHasher>
Modules;
- std::unordered_map<ModuleID, std::string, ModuleIDHasher> PCMPaths;
std::vector<InputDeps> Inputs;
};
@@ -432,19 +412,231 @@ static bool handleFullDependencyToolResult(
return false;
}
-int main(int argc, const char **argv) {
+class P1689Deps {
+public:
+ void printDependencies(raw_ostream &OS) {
+ addSourcePathsToRequires();
+ // Sort the modules by name to get a deterministic order.
+ llvm::sort(Rules, [](const P1689Rule &A, const P1689Rule &B) {
+ return A.PrimaryOutput < B.PrimaryOutput;
+ });
+
+ using namespace llvm::json;
+ Array OutputRules;
+ for (const P1689Rule &R : Rules) {
+ Object O{{"primary-output", R.PrimaryOutput}};
+
+ if (R.Provides) {
+ Array Provides;
+ Object Provided{{"logical-name", R.Provides->ModuleName},
+ {"source-path", R.Provides->SourcePath},
+ {"is-interface", R.Provides->IsStdCXXModuleInterface}};
+ Provides.push_back(std::move(Provided));
+ O.insert({"provides", std::move(Provides)});
+ }
+
+ Array Requires;
+ for (const P1689ModuleInfo &Info : R.Requires) {
+ Object RequiredInfo{{"logical-name", Info.ModuleName}};
+ if (!Info.SourcePath.empty())
+ RequiredInfo.insert({"source-path", Info.SourcePath});
+ Requires.push_back(std::move(RequiredInfo));
+ }
+
+ if (!Requires.empty())
+ O.insert({"requires", std::move(Requires)});
+
+ OutputRules.push_back(std::move(O));
+ }
+
+ Object Output{
+ {"version", 1}, {"revision", 0}, {"rules", std::move(OutputRules)}};
+
+ OS << llvm::formatv("{0:2}\n", Value(std::move(Output)));
+ }
+
+ void addRules(P1689Rule &Rule) {
+ std::unique_lock<std::mutex> LockGuard(Lock);
+ Rules.push_back(Rule);
+ }
+
+private:
+ void addSourcePathsToRequires() {
+ llvm::DenseMap<StringRef, StringRef> ModuleSourceMapper;
+ for (const P1689Rule &R : Rules)
+ if (R.Provides && !R.Provides->SourcePath.empty())
+ ModuleSourceMapper[R.Provides->ModuleName] = R.Provides->SourcePath;
+
+ for (P1689Rule &R : Rules) {
+ for (P1689ModuleInfo &Info : R.Requires) {
+ auto Iter = ModuleSourceMapper.find(Info.ModuleName);
+ if (Iter != ModuleSourceMapper.end())
+ Info.SourcePath = Iter->second;
+ }
+ }
+ }
+
+ std::mutex Lock;
+ std::vector<P1689Rule> Rules;
+};
+
+static bool
+handleP1689DependencyToolResult(const std::string &Input,
+ llvm::Expected<P1689Rule> &MaybeRule,
+ P1689Deps &PD, SharedStream &Errs) {
+ if (!MaybeRule) {
+ llvm::handleAllErrors(
+ MaybeRule.takeError(), [&Input, &Errs](llvm::StringError &Err) {
+ Errs.applyLocked([&](raw_ostream &OS) {
+ OS << "Error while scanning dependencies for " << Input << ":\n";
+ OS << Err.getMessage();
+ });
+ });
+ return true;
+ }
+ PD.addRules(*MaybeRule);
+ return false;
+}
+
+/// Construct a path for the explicitly built PCM.
+static std::string constructPCMPath(ModuleID MID, StringRef OutputDir) {
+ SmallString<256> ExplicitPCMPath(OutputDir);
+ llvm::sys::path::append(ExplicitPCMPath, MID.ContextHash,
+ MID.ModuleName + "-" + MID.ContextHash + ".pcm");
+ return std::string(ExplicitPCMPath);
+}
+
+static std::string lookupModuleOutput(const ModuleID &MID, ModuleOutputKind MOK,
+ StringRef OutputDir) {
+ std::string PCMPath = constructPCMPath(MID, OutputDir);
+ switch (MOK) {
+ case ModuleOutputKind::ModuleFile:
+ return PCMPath;
+ case ModuleOutputKind::DependencyFile:
+ return PCMPath + ".d";
+ case ModuleOutputKind::DependencyTargets:
+ // Null-separate the list of targets.
+ return join(ModuleDepTargets, StringRef("\0", 1));
+ case ModuleOutputKind::DiagnosticSerializationFile:
+ return PCMPath + ".diag";
+ }
+ llvm_unreachable("Fully covered switch above!");
+}
+
+static std::string getModuleCachePath(ArrayRef<std::string> Args) {
+ for (StringRef Arg : llvm::reverse(Args)) {
+ Arg.consume_front("/clang:");
+ if (Arg.consume_front("-fmodules-cache-path="))
+ return std::string(Arg);
+ }
+ SmallString<128> Path;
+ driver::Driver::getDefaultModuleCachePath(Path);
+ return std::string(Path);
+}
+
+// getCompilationDataBase - If -compilation-database is set, load the
+// compilation database from the specified file. Otherwise if the we're
+// generating P1689 format, trying to generate the compilation database
+// form specified command line after the positional parameter "--".
+static std::unique_ptr<tooling::CompilationDatabase>
+getCompilationDataBase(int argc, const char **argv, std::string &ErrorMessage) {
llvm::InitLLVM X(argc, argv);
llvm::cl::HideUnrelatedOptions(DependencyScannerCategory);
if (!llvm::cl::ParseCommandLineOptions(argc, argv))
- return 1;
+ return nullptr;
+
+ if (!CompilationDB.empty())
+ return tooling::JSONCompilationDatabase::loadFromFile(
+ CompilationDB, ErrorMessage,
+ tooling::JSONCommandLineSyntax::AutoDetect);
+
+ if (Format != ScanningOutputFormat::P1689) {
+ llvm::errs() << "the --compilation-database option: must be specified at "
+ "least once!";
+ return nullptr;
+ }
+
+ // Trying to get the input file, the output file and the command line options
+ // from the positional parameter "--".
+ const char **DoubleDash = std::find(argv, argv + argc, StringRef("--"));
+ if (DoubleDash == argv + argc) {
+ llvm::errs() << "The command line arguments is required after '--' in "
+ "P1689 per file mode.";
+ return nullptr;
+ }
+ std::vector<const char *> CommandLine(DoubleDash + 1, argv + argc);
+
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ CompilerInstance::createDiagnostics(new DiagnosticOptions);
+ driver::Driver TheDriver(CommandLine[0], llvm::sys::getDefaultTargetTriple(),
+ *Diags);
+ std::unique_ptr<driver::Compilation> C(
+ TheDriver.BuildCompilation(CommandLine));
+ if (!C)
+ return nullptr;
+
+ auto Cmd = C->getJobs().begin();
+ auto CI = std::make_unique<CompilerInvocation>();
+ CompilerInvocation::CreateFromArgs(*CI, Cmd->getArguments(), *Diags,
+ CommandLine[0]);
+ if (!CI)
+ return nullptr;
+
+ FrontendOptions &FEOpts = CI->getFrontendOpts();
+ if (FEOpts.Inputs.size() != 1) {
+ llvm::errs() << "Only one input file is allowed in P1689 per file mode.";
+ return nullptr;
+ }
+
+ // There might be multiple jobs for a compilation. Extract the specified
+ // output filename from the last job.
+ auto LastCmd = C->getJobs().end();
+ LastCmd--;
+ if (LastCmd->getOutputFilenames().size() != 1) {
+ llvm::errs() << "The command line should provide exactly one output file "
+ "in P1689 per file mode.\n";
+ }
+ StringRef OutputFile = LastCmd->getOutputFilenames().front();
+
+ class InplaceCompilationDatabase : public tooling::CompilationDatabase {
+ public:
+ InplaceCompilationDatabase(StringRef InputFile, StringRef OutputFile,
+ ArrayRef<const char *> CommandLine)
+ : Command(".", InputFile, {}, OutputFile) {
+ for (auto *C : CommandLine)
+ Command.CommandLine.push_back(C);
+ }
+
+ std::vector<tooling::CompileCommand>
+ getCompileCommands(StringRef FilePath) const override {
+ if (FilePath != Command.Filename)
+ return {};
+ return {Command};
+ }
+
+ std::vector<std::string> getAllFiles() const override {
+ return {Command.Filename};
+ }
+ std::vector<tooling::CompileCommand>
+ getAllCompileCommands() const override {
+ return {Command};
+ }
+
+ private:
+ tooling::CompileCommand Command;
+ };
+
+ return std::make_unique<InplaceCompilationDatabase>(
+ FEOpts.Inputs[0].getFile(), OutputFile, CommandLine);
+}
+
+int main(int argc, const char **argv) {
std::string ErrorMessage;
- std::unique_ptr<tooling::JSONCompilationDatabase> Compilations =
- tooling::JSONCompilationDatabase::loadFromFile(
- CompilationDB, ErrorMessage,
- tooling::JSONCommandLineSyntax::AutoDetect);
+ std::unique_ptr<tooling::CompilationDatabase> Compilations =
+ getCompilationDataBase(argc, argv, ErrorMessage);
if (!Compilations) {
- llvm::errs() << "error: " << ErrorMessage << "\n";
+ llvm::errs() << ErrorMessage << "\n";
return 1;
}
@@ -459,7 +651,7 @@ int main(int argc, const char **argv) {
AdjustingCompilations->appendArgumentsAdjuster(
[&ResourceDirCache](const tooling::CommandLineArguments &Args,
StringRef FileName) {
- std::string LastO = "";
+ std::string LastO;
bool HasResourceDir = false;
bool ClangCLMode = false;
auto FlagsEnd = llvm::find(Args, "--");
@@ -469,7 +661,7 @@ int main(int argc, const char **argv) {
llvm::is_contained(Args, "--driver-mode=cl");
// Reverse scan, starting at the end or at the element before "--".
- auto R = llvm::make_reverse_iterator(FlagsEnd);
+ auto R = std::make_reverse_iterator(FlagsEnd);
for (auto I = R, E = Args.rend(); I != E; ++I) {
StringRef Arg = *I;
if (ClangCLMode) {
@@ -503,7 +695,7 @@ int main(int argc, const char **argv) {
AdjustedArgs.push_back("/clang:" + LastO);
}
- if (!HasResourceDir) {
+ if (!HasResourceDir && ResourceDirRecipe == RDRK_InvokeCompiler) {
StringRef ResourceDir =
ResourceDirCache.findResourceDir(Args, ClangCLMode);
if (!ResourceDir.empty()) {
@@ -519,20 +711,19 @@ int main(int argc, const char **argv) {
// Print out the dependency results to STDOUT by default.
SharedStream DependencyOS(llvm::outs());
- DependencyScanningService Service(ScanMode, Format, ReuseFileManager,
- SkipExcludedPPRanges);
+ DependencyScanningService Service(ScanMode, Format, OptimizeArgs,
+ EagerLoadModules);
llvm::ThreadPool Pool(llvm::hardware_concurrency(NumThreads));
std::vector<std::unique_ptr<DependencyScanningTool>> WorkerTools;
for (unsigned I = 0; I < Pool.getThreadCount(); ++I)
WorkerTools.push_back(std::make_unique<DependencyScanningTool>(Service));
- std::vector<SingleCommandCompilationDatabase> Inputs;
- for (tooling::CompileCommand Cmd :
- AdjustingCompilations->getAllCompileCommands())
- Inputs.emplace_back(Cmd);
+ std::vector<tooling::CompileCommand> Inputs =
+ AdjustingCompilations->getAllCompileCommands();
std::atomic<bool> HadErrors(false);
FullDeps FD;
+ P1689Deps PD;
std::mutex Lock;
size_t Index = 0;
@@ -541,11 +732,11 @@ int main(int argc, const char **argv) {
<< " files using " << Pool.getThreadCount() << " workers\n";
}
for (unsigned I = 0; I < Pool.getThreadCount(); ++I) {
- Pool.async([I, &Lock, &Index, &Inputs, &HadErrors, &FD, &WorkerTools,
+ Pool.async([I, &Lock, &Index, &Inputs, &HadErrors, &FD, &PD, &WorkerTools,
&DependencyOS, &Errs]() {
llvm::StringSet<> AlreadySeenModules;
while (true) {
- const SingleCommandCompilationDatabase *Input;
+ const tooling::CompileCommand *Input;
std::string Filename;
std::string CWD;
size_t LocalIndex;
@@ -556,19 +747,80 @@ int main(int argc, const char **argv) {
return;
LocalIndex = Index;
Input = &Inputs[Index++];
- tooling::CompileCommand Cmd = Input->getAllCompileCommands()[0];
- Filename = std::move(Cmd.Filename);
- CWD = std::move(Cmd.Directory);
+ Filename = std::move(Input->Filename);
+ CWD = std::move(Input->Directory);
}
+ std::optional<StringRef> MaybeModuleName;
+ if (!ModuleName.empty())
+ MaybeModuleName = ModuleName;
+
+ std::string OutputDir(ModuleFilesDir);
+ if (OutputDir.empty())
+ OutputDir = getModuleCachePath(Input->CommandLine);
+ auto LookupOutput = [&](const ModuleID &MID, ModuleOutputKind MOK) {
+ return ::lookupModuleOutput(MID, MOK, OutputDir);
+ };
+
// Run the tool on it.
if (Format == ScanningOutputFormat::Make) {
- auto MaybeFile = WorkerTools[I]->getDependencyFile(*Input, CWD);
+ auto MaybeFile = WorkerTools[I]->getDependencyFile(
+ Input->CommandLine, CWD, MaybeModuleName);
if (handleMakeDependencyToolResult(Filename, MaybeFile, DependencyOS,
Errs))
HadErrors = true;
+ } else if (Format == ScanningOutputFormat::P1689) {
+ // It is useful to generate the make-format dependency output during
+ // the scanning for P1689. Otherwise the users need to scan again for
+ // it. We will generate the make-format dependency output if we find
+ // `-MF` in the command lines.
+ std::string MakeformatOutputPath;
+ std::string MakeformatOutput;
+
+ auto MaybeRule = WorkerTools[I]->getP1689ModuleDependencyFile(
+ *Input, CWD, MakeformatOutput, MakeformatOutputPath);
+ HadErrors =
+ handleP1689DependencyToolResult(Filename, MaybeRule, PD, Errs);
+
+ if (!MakeformatOutputPath.empty() && !MakeformatOutput.empty() &&
+ !HadErrors) {
+ static std::mutex Lock;
+ // With compilation database, we may open different files
+ // concurrently or we may write the same file concurrently. So we
+ // use a map here to allow multiple compile commands to write to the
+ // same file. Also we need a lock here to avoid data race.
+ static llvm::StringMap<llvm::raw_fd_ostream> OSs;
+ std::unique_lock<std::mutex> LockGuard(Lock);
+
+ auto OSIter = OSs.find(MakeformatOutputPath);
+ if (OSIter == OSs.end()) {
+ std::error_code EC;
+ OSIter = OSs.try_emplace(MakeformatOutputPath,
+ MakeformatOutputPath, EC)
+ .first;
+ if (EC)
+ llvm::errs()
+ << "Failed to open P1689 make format output file \""
+ << MakeformatOutputPath << "\" for " << EC.message()
+ << "\n";
+ }
+
+ SharedStream MakeformatOS(OSIter->second);
+ llvm::Expected<std::string> MaybeOutput(MakeformatOutput);
+ HadErrors = handleMakeDependencyToolResult(Filename, MaybeOutput,
+ MakeformatOS, Errs);
+ }
+ } else if (DeprecatedDriverCommand) {
+ auto MaybeFullDeps =
+ WorkerTools[I]->getFullDependenciesLegacyDriverCommand(
+ Input->CommandLine, CWD, AlreadySeenModules, LookupOutput,
+ MaybeModuleName);
+ if (handleFullDependencyToolResult(Filename, MaybeFullDeps, FD,
+ LocalIndex, DependencyOS, Errs))
+ HadErrors = true;
} else {
auto MaybeFullDeps = WorkerTools[I]->getFullDependencies(
- *Input, CWD, AlreadySeenModules);
+ Input->CommandLine, CWD, AlreadySeenModules, LookupOutput,
+ MaybeModuleName);
if (handleFullDependencyToolResult(Filename, MaybeFullDeps, FD,
LocalIndex, DependencyOS, Errs))
HadErrors = true;
@@ -580,6 +832,8 @@ int main(int argc, const char **argv) {
if (Format == ScanningOutputFormat::Full)
FD.printFullOutput(llvm::outs());
+ else if (Format == ScanningOutputFormat::P1689)
+ PD.printDependencies(llvm::outs());
return HadErrors;
}
diff --git a/gnu/llvm/clang/tools/diag-build/diag-build.sh b/gnu/llvm/clang/tools/diag-build/diag-build.sh
index 018288dda95..b1504ffcc41 100755
--- a/gnu/llvm/clang/tools/diag-build/diag-build.sh
+++ b/gnu/llvm/clang/tools/diag-build/diag-build.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# diag-build: a tool showing enabled warnings in a project.
#
diff --git a/gnu/llvm/clang/tools/diagtool/DiagTool.cpp b/gnu/llvm/clang/tools/diagtool/DiagTool.cpp
index 81d4e7e44cc..99abe5755f7 100644
--- a/gnu/llvm/clang/tools/diagtool/DiagTool.cpp
+++ b/gnu/llvm/clang/tools/diagtool/DiagTool.cpp
@@ -12,6 +12,7 @@
#include "DiagTool.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/STLExtras.h"
#include <vector>
using namespace diagtool;
diff --git a/gnu/llvm/clang/tools/diagtool/DiagnosticNames.cpp b/gnu/llvm/clang/tools/diagtool/DiagnosticNames.cpp
index c54f81481a2..852b8c226e8 100644
--- a/gnu/llvm/clang/tools/diagtool/DiagnosticNames.cpp
+++ b/gnu/llvm/clang/tools/diagtool/DiagnosticNames.cpp
@@ -20,16 +20,16 @@ static const DiagnosticRecord BuiltinDiagnosticsByName[] = {
};
llvm::ArrayRef<DiagnosticRecord> diagtool::getBuiltinDiagnosticsByName() {
- return llvm::makeArrayRef(BuiltinDiagnosticsByName);
+ return llvm::ArrayRef(BuiltinDiagnosticsByName);
}
// FIXME: Is it worth having two tables, especially when this one can get
// out of sync easily?
static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
-#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
- SFINAE,NOWERROR,SHOWINSYSHEADER,DEFER,CATEGORY) \
- { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
+#define DIAG(ENUM, CLASS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \
+ SHOWINSYSHEADER, SHOWINSYSMACRO, DEFER, CATEGORY) \
+ {#ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t)},
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticCrossTUKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
@@ -66,9 +66,10 @@ const DiagnosticRecord &diagtool::getDiagnosticForID(short DiagID) {
// Second the table of options, sorted by name for fast binary lookup.
static const GroupRecord OptionTable[] = {
-#define GET_DIAG_TABLE
+#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
+ {FlagNameOffset, Members, SubGroups},
#include "clang/Basic/DiagnosticGroups.inc"
-#undef GET_DIAG_TABLE
+#undef DIAG_ENTRY
};
llvm::StringRef GroupRecord::getName() const {
@@ -102,5 +103,5 @@ GroupRecord::diagnostics() const {
}
llvm::ArrayRef<GroupRecord> diagtool::getDiagnosticGroups() {
- return llvm::makeArrayRef(OptionTable);
+ return llvm::ArrayRef(OptionTable);
}
diff --git a/gnu/llvm/clang/tools/diagtool/FindDiagnosticID.cpp b/gnu/llvm/clang/tools/diagtool/FindDiagnosticID.cpp
index 2a08814478f..6ced701f563 100644
--- a/gnu/llvm/clang/tools/diagtool/FindDiagnosticID.cpp
+++ b/gnu/llvm/clang/tools/diagtool/FindDiagnosticID.cpp
@@ -10,6 +10,7 @@
#include "DiagnosticNames.h"
#include "clang/Basic/AllDiagnostics.h"
#include "llvm/Support/CommandLine.h"
+#include <optional>
DEF_DIAGTOOL("find-diagnostic-id", "Print the id of the given diagnostic",
FindDiagnosticID)
@@ -26,14 +27,14 @@ static StringRef getNameFromID(StringRef Name) {
return StringRef();
}
-static Optional<DiagnosticRecord>
+static std::optional<DiagnosticRecord>
findDiagnostic(ArrayRef<DiagnosticRecord> Diagnostics, StringRef Name) {
for (const auto &Diag : Diagnostics) {
StringRef DiagName = Diag.getName();
if (DiagName == Name)
return Diag;
}
- return None;
+ return std::nullopt;
}
int FindDiagnosticID::run(unsigned int argc, char **argv,
@@ -47,7 +48,7 @@ int FindDiagnosticID::run(unsigned int argc, char **argv,
std::vector<const char *> Args;
Args.push_back("diagtool find-diagnostic-id");
- for (const char *A : llvm::makeArrayRef(argv, argc))
+ for (const char *A : llvm::ArrayRef(argv, argc))
Args.push_back(A);
llvm::cl::HideUnrelatedOptions(FindDiagnosticIDOptions);
@@ -55,7 +56,7 @@ int FindDiagnosticID::run(unsigned int argc, char **argv,
"Diagnostic ID mapping utility");
ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
- Optional<DiagnosticRecord> Diag =
+ std::optional<DiagnosticRecord> Diag =
findDiagnostic(AllDiagnostics, DiagnosticName);
if (!Diag) {
// Name to id failed, so try id to name.
diff --git a/gnu/llvm/clang/tools/diagtool/ShowEnabledWarnings.cpp b/gnu/llvm/clang/tools/diagtool/ShowEnabledWarnings.cpp
index ae2d3e37e84..285efe6ae05 100644
--- a/gnu/llvm/clang/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/gnu/llvm/clang/tools/diagtool/ShowEnabledWarnings.cpp
@@ -59,15 +59,16 @@ createDiagnostics(unsigned int argc, char **argv) {
// Buffer diagnostics from argument parsing so that we can output them using a
// well formed diagnostic object.
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
- IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags(
- new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer));
// Try to build a CompilerInvocation.
SmallVector<const char *, 4> Args;
Args.push_back("diagtool");
Args.append(argv, argv + argc);
+ CreateInvocationOptions CIOpts;
+ CIOpts.Diags =
+ new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer);
std::unique_ptr<CompilerInvocation> Invocation =
- createInvocationFromCommandLine(Args, InterimDiags);
+ createInvocation(Args, CIOpts);
if (!Invocation)
return nullptr;
diff --git a/gnu/llvm/clang/tools/diagtool/TreeView.cpp b/gnu/llvm/clang/tools/diagtool/TreeView.cpp
index 843bd377e57..92d92aa9069 100644
--- a/gnu/llvm/clang/tools/diagtool/TreeView.cpp
+++ b/gnu/llvm/clang/tools/diagtool/TreeView.cpp
@@ -40,11 +40,7 @@ public:
if (!Group.diagnostics().empty())
return false;
- for (const GroupRecord &GR : Group.subgroups())
- if (!unimplemented(GR))
- return false;
-
- return true;
+ return llvm::all_of(Group.subgroups(), unimplemented);
}
static bool enabledByDefault(const GroupRecord &Group) {
diff --git a/gnu/llvm/clang/tools/driver/CMakeLists.txt b/gnu/llvm/clang/tools/driver/CMakeLists.txt
index 7c32aadb870..237ed453e28 100644
--- a/gnu/llvm/clang/tools/driver/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/driver/CMakeLists.txt
@@ -13,12 +13,11 @@ set( LLVM_LINK_COMPONENTS
Option
ScalarOpts
Support
+ TargetParser
TransformUtils
Vectorize
)
-option(CLANG_PLUGIN_SUPPORT "Build clang with plugin support" ON)
-
# Support plugins.
if(CLANG_PLUGIN_SUPPORT)
set(support_plugins SUPPORT_PLUGINS)
@@ -33,6 +32,7 @@ add_clang_tool(clang
DEPENDS
intrinsics_gen
${support_plugins}
+ GENERATE_DRIVER
)
clang_target_link_libraries(clang
@@ -62,7 +62,11 @@ if(NOT CLANG_LINKS_TO_CREATE)
set(CLANG_LINKS_TO_CREATE clang++ clang-cl clang-cpp)
endif()
-foreach(link ${CLANG_LINKS_TO_CREATE})
+if (CLANG_ENABLE_HLSL)
+ set(HLSL_LINK clang-dxc)
+endif()
+
+foreach(link ${CLANG_LINKS_TO_CREATE} ${HLSL_LINK})
add_clang_symlink(${link} clang)
endforeach()
@@ -82,7 +86,7 @@ if (APPLE)
set(TOOL_INFO_PLIST_OUT "${CMAKE_CURRENT_BINARY_DIR}/${TOOL_INFO_PLIST}")
target_link_libraries(clang
PRIVATE
- "-Wl,-sectcreate,__TEXT,__info_plist,${TOOL_INFO_PLIST_OUT}")
+ "-Wl,-sectcreate,__TEXT,__info_plist,\"${TOOL_INFO_PLIST_OUT}\"")
configure_file("${TOOL_INFO_PLIST}.in" "${TOOL_INFO_PLIST_OUT}" @ONLY)
set(TOOL_INFO_UTI)
@@ -95,7 +99,7 @@ if(CLANG_ORDER_FILE AND
(LLVM_LINKER_IS_LD64 OR LLVM_LINKER_IS_GOLD OR LLVM_LINKER_IS_LLD))
include(LLVMCheckLinkerFlag)
- if (LLVM_LINKER_IS_LD64)
+ if (LLVM_LINKER_IS_LD64 OR (LLVM_LINKER_IS_LLD AND APPLE))
set(LINKER_ORDER_FILE_OPTION "-Wl,-order_file,${CLANG_ORDER_FILE}")
elseif (LLVM_LINKER_IS_GOLD)
set(LINKER_ORDER_FILE_OPTION "-Wl,--section-ordering-file,${CLANG_ORDER_FILE}")
diff --git a/gnu/llvm/clang/tools/driver/cc1_main.cpp b/gnu/llvm/clang/tools/driver/cc1_main.cpp
index 396d6ff529f..c79306b6f7d 100644
--- a/gnu/llvm/clang/tools/driver/cc1_main.cpp
+++ b/gnu/llvm/clang/tools/driver/cc1_main.cpp
@@ -28,6 +28,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/LinkAllPasses.h"
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
@@ -38,7 +39,6 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
-#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/Timer.h"
@@ -57,7 +57,7 @@ using namespace llvm::opt;
// Main driver
//===----------------------------------------------------------------------===//
-static void LLVMErrorHandler(void *UserData, const std::string &Message,
+static void LLVMErrorHandler(void *UserData, const char *Message,
bool GenCrashDiag) {
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
@@ -177,7 +177,8 @@ static int PrintSupportedCPUs(std::string TargetStr) {
// the target machine will handle the mcpu printing
llvm::TargetOptions Options;
std::unique_ptr<llvm::TargetMachine> TheTargetMachine(
- TheTarget->createTargetMachine(TargetStr, "", "+cpuhelp", Options, None));
+ TheTarget->createTargetMachine(TargetStr, "", "+cpuhelp", Options,
+ std::nullopt));
return 0;
}
@@ -212,7 +213,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
Argv, Diags, Argv0);
- if (Clang->getFrontendOpts().TimeTrace) {
+ if (Clang->getFrontendOpts().TimeTrace ||
+ !Clang->getFrontendOpts().TimeTracePath.empty()) {
+ Clang->getFrontendOpts().TimeTrace = 1;
llvm::timeTraceProfilerInitialize(
Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
}
@@ -237,8 +240,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
static_cast<void*>(&Clang->getDiagnostics()));
DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
- if (!Success)
+ if (!Success) {
+ Clang->getDiagnosticClient().finish();
return 1;
+ }
// Execute the frontend actions.
{
@@ -254,12 +259,18 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
if (llvm::timeTraceProfilerEnabled()) {
SmallString<128> Path(Clang->getFrontendOpts().OutputFile);
llvm::sys::path::replace_extension(Path, "json");
+ if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
+ // replace the suffix to '.json' directly
+ SmallString<128> TracePath(Clang->getFrontendOpts().TimeTracePath);
+ if (llvm::sys::fs::is_directory(TracePath))
+ llvm::sys::path::append(TracePath, llvm::sys::path::filename(Path));
+ Path.assign(TracePath);
+ }
if (auto profilerOutput = Clang->createOutputFile(
Path.str(), /*Binary=*/false, /*RemoveFileOnSignal=*/false,
/*useTemporary=*/false)) {
llvm::timeTraceProfilerWrite(*profilerOutput);
- // FIXME(ibiryukov): make profilerOutput flush in destructor instead.
- profilerOutput->flush();
+ profilerOutput.reset();
llvm::timeTraceProfilerCleanup();
Clang->clearOutputFiles(false);
}
diff --git a/gnu/llvm/clang/tools/driver/cc1as_main.cpp b/gnu/llvm/clang/tools/driver/cc1as_main.cpp
index 086ce0ea778..f944113476f 100644
--- a/gnu/llvm/clang/tools/driver/cc1as_main.cpp
+++ b/gnu/llvm/clang/tools/driver/cc1as_main.cpp
@@ -36,6 +36,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
@@ -49,11 +50,11 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
+#include <optional>
#include <system_error>
using namespace clang;
using namespace clang::driver;
@@ -134,9 +135,13 @@ struct AssemblerInvocation {
unsigned NoExecStack : 1;
unsigned FatalWarnings : 1;
unsigned NoWarn : 1;
+ unsigned NoTypeCheck : 1;
unsigned IncrementalLinkerCompatible : 1;
unsigned EmbedBitcode : 1;
+ /// Whether to emit DWARF unwind info.
+ EmitDwarfUnwindType EmitDwarfUnwind;
+
/// The name of the relocation model to use.
std::string RelocationModel;
@@ -144,6 +149,16 @@ struct AssemblerInvocation {
/// otherwise.
std::string TargetABI;
+ /// Darwin target variant triple, the variant of the deployment target
+ /// for which the code is being compiled.
+ std::optional<llvm::Triple> DarwinTargetVariantTriple;
+
+ /// The version of the darwin target variant SDK which was used during the
+ /// compilation
+ llvm::VersionTuple DarwinTargetVariantSDKVersion;
+
+ /// The name of a file to use with \c .secure_log_unique directives.
+ std::string AsSecureLogFile;
/// @}
public:
@@ -160,10 +175,12 @@ public:
NoExecStack = 0;
FatalWarnings = 0;
NoWarn = 0;
+ NoTypeCheck = 0;
IncrementalLinkerCompatible = 0;
Dwarf64 = 0;
DwarfVersion = 0;
EmbedBitcode = 0;
+ EmitDwarfUnwind = EmitDwarfUnwindType::Default;
}
static bool CreateFromArgs(AssemblerInvocation &Res,
@@ -209,6 +226,17 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Target Options
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
+ if (Arg *A = Args.getLastArg(options::OPT_darwin_target_variant_triple))
+ Opts.DarwinTargetVariantTriple = llvm::Triple(A->getValue());
+ if (Arg *A = Args.getLastArg(OPT_darwin_target_variant_sdk_version_EQ)) {
+ VersionTuple Version;
+ if (Version.tryParse(A->getValue()))
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ else
+ Opts.DarwinTargetVariantSDKVersion = Version;
+ }
+
Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
Opts.Features = Args.getAllArgValues(OPT_target_feature);
@@ -227,12 +255,12 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
- .Case("zlib", llvm::DebugCompressionType::Z)
- .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
+ .Case("zlib", llvm::DebugCompressionType::Zlib)
+ .Case("zstd", llvm::DebugCompressionType::Zstd)
.Default(llvm::DebugCompressionType::None);
}
- Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
+ Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
@@ -295,6 +323,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
+ Opts.NoTypeCheck = Args.hasArg(OPT_mno_type_check);
Opts.RelocationModel =
std::string(Args.getLastArgValue(OPT_mrelocation_model, "pic"));
Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi));
@@ -312,6 +341,16 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
.Default(0);
}
+ if (auto *A = Args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
+ Opts.EmitDwarfUnwind =
+ llvm::StringSwitch<EmitDwarfUnwindType>(A->getValue())
+ .Case("always", EmitDwarfUnwindType::Always)
+ .Case("no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
+ .Case("default", EmitDwarfUnwindType::Default);
+ }
+
+ Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
+
return Success;
}
@@ -362,6 +401,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
assert(MRI && "Unable to create target register info!");
MCTargetOptions MCOptions;
+ MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
+ MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
+
std::unique_ptr<MCAsmInfo> MAI(
TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
assert(MAI && "Unable to create target asm info!");
@@ -408,6 +450,10 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(
TheTarget->createMCObjectFileInfo(Ctx, PIC));
+ if (Opts.DarwinTargetVariantTriple)
+ MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
+ if (!Opts.DarwinTargetVariantSDKVersion.empty())
+ MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
Ctx.setObjectFileInfo(MOFI.get());
if (Opts.SaveTemporaryLabels)
@@ -447,6 +493,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
MCOptions.MCNoWarn = Opts.NoWarn;
MCOptions.MCFatalWarnings = Opts.FatalWarnings;
+ MCOptions.MCNoTypeCheck = Opts.NoTypeCheck;
MCOptions.ABIName = Opts.TargetABI;
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
@@ -456,7 +503,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
std::unique_ptr<MCCodeEmitter> CE;
if (Opts.ShowEncoding)
- CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+ CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
@@ -476,7 +523,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
}
std::unique_ptr<MCCodeEmitter> CE(
- TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+ TheTarget->createMCCodeEmitter(*MCII, Ctx));
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
assert(MAB && "Unable to create asm backend!");
@@ -490,7 +537,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ true));
- Str.get()->InitSections(Opts.NoExecStack);
+ Str.get()->initSections(Opts.NoExecStack, *STI);
}
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
@@ -498,7 +545,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
MCSection *AsmLabel = Ctx.getMachOSection(
"__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
- Str.get()->SwitchSection(AsmLabel);
+ Str.get()->switchSection(AsmLabel);
Str.get()->emitZeros(1);
}
@@ -550,7 +597,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
return Failed;
}
-static void LLVMErrorHandler(void *UserData, const std::string &Message,
+static void LLVMErrorHandler(void *UserData, const char *Message,
bool GenCrashDiag) {
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
diff --git a/gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp b/gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp
index 89b7227fdb1..9dbfc518add 100644
--- a/gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp
+++ b/gnu/llvm/clang/tools/driver/cc1gen_reproducer_main.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
@@ -108,7 +109,7 @@ static std::string generateReproducerMetaInfo(const ClangInvocationInfo &Info) {
}
/// Generates a reproducer for a set of arguments from a specific invocation.
-static llvm::Optional<driver::Driver::CompilationDiagnosticReport>
+static std::optional<driver::Driver::CompilationDiagnosticReport>
generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
const ClangInvocationInfo &Info) {
using namespace driver;
@@ -134,7 +135,7 @@ generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
}
}
- return None;
+ return std::nullopt;
}
std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes);
@@ -180,7 +181,7 @@ int cc1gen_reproducer_main(ArrayRef<const char *> Argv, const char *Argv0,
DriverArgs.push_back(Arg.c_str());
std::string Path = GetExecutablePath(Argv0, /*CanonicalPrefixes=*/true);
DriverArgs[0] = Path.c_str();
- llvm::Optional<driver::Driver::CompilationDiagnosticReport> Report =
+ std::optional<driver::Driver::CompilationDiagnosticReport> Report =
generateReproducerForInvocationArguments(DriverArgs, InvocationInfo);
// Emit the information about the reproduce files to stdout.
diff --git a/gnu/llvm/clang/tools/driver/driver.cpp b/gnu/llvm/clang/tools/driver/driver.cpp
index 5a453429e79..d7474123365 100644
--- a/gnu/llvm/clang/tools/driver/driver.cpp
+++ b/gnu/llvm/clang/tools/driver/driver.cpp
@@ -13,6 +13,7 @@
#include "clang/Driver/Driver.h"
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/HeaderInclude.h"
#include "clang/Basic/Stack.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
@@ -48,6 +49,7 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
+#include <optional>
#include <set>
#include <system_error>
using namespace clang;
@@ -120,7 +122,7 @@ static void ApplyOneQAOverride(raw_ostream &OS,
OS << "### Adding argument " << Str << " at end\n";
Args.push_back(Str);
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
- Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) {
+ Edit.slice(2, Edit.size() - 1).contains('/')) {
StringRef MatchPattern = Edit.substr(2).split('/').first;
StringRef ReplPattern = Edit.substr(2).split('/').second;
ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
@@ -243,29 +245,68 @@ static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
*NumberSignPtr = '=';
}
-static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
- auto CheckEnvVar = [](const char *EnvOptSet, const char *EnvOptFile,
- std::string &OptFile) {
- bool OptSet = !!::getenv(EnvOptSet);
- if (OptSet) {
- if (const char *Var = ::getenv(EnvOptFile))
- OptFile = Var;
- }
- return OptSet;
- };
+template <class T>
+static T checkEnvVar(const char *EnvOptSet, const char *EnvOptFile,
+ std::string &OptFile) {
+ const char *Str = ::getenv(EnvOptSet);
+ if (!Str)
+ return T{};
+
+ T OptVal = Str;
+ if (const char *Var = ::getenv(EnvOptFile))
+ OptFile = Var;
+ return OptVal;
+}
+static bool SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
TheDriver.CCPrintOptions =
- CheckEnvVar("CC_PRINT_OPTIONS", "CC_PRINT_OPTIONS_FILE",
- TheDriver.CCPrintOptionsFilename);
- TheDriver.CCPrintHeaders =
- CheckEnvVar("CC_PRINT_HEADERS", "CC_PRINT_HEADERS_FILE",
- TheDriver.CCPrintHeadersFilename);
+ checkEnvVar<bool>("CC_PRINT_OPTIONS", "CC_PRINT_OPTIONS_FILE",
+ TheDriver.CCPrintOptionsFilename);
+ if (checkEnvVar<bool>("CC_PRINT_HEADERS", "CC_PRINT_HEADERS_FILE",
+ TheDriver.CCPrintHeadersFilename)) {
+ TheDriver.CCPrintHeadersFormat = HIFMT_Textual;
+ TheDriver.CCPrintHeadersFiltering = HIFIL_None;
+ } else {
+ std::string EnvVar = checkEnvVar<std::string>(
+ "CC_PRINT_HEADERS_FORMAT", "CC_PRINT_HEADERS_FILE",
+ TheDriver.CCPrintHeadersFilename);
+ if (!EnvVar.empty()) {
+ TheDriver.CCPrintHeadersFormat =
+ stringToHeaderIncludeFormatKind(EnvVar.c_str());
+ if (!TheDriver.CCPrintHeadersFormat) {
+ TheDriver.Diag(clang::diag::err_drv_print_header_env_var)
+ << 0 << EnvVar;
+ return false;
+ }
+
+ const char *FilteringStr = ::getenv("CC_PRINT_HEADERS_FILTERING");
+ HeaderIncludeFilteringKind Filtering;
+ if (!stringToHeaderIncludeFiltering(FilteringStr, Filtering)) {
+ TheDriver.Diag(clang::diag::err_drv_print_header_env_var)
+ << 1 << FilteringStr;
+ return false;
+ }
+
+ if ((TheDriver.CCPrintHeadersFormat == HIFMT_Textual &&
+ Filtering != HIFIL_None) ||
+ (TheDriver.CCPrintHeadersFormat == HIFMT_JSON &&
+ Filtering != HIFIL_Only_Direct_System)) {
+ TheDriver.Diag(clang::diag::err_drv_print_header_env_var_combination)
+ << EnvVar << FilteringStr;
+ return false;
+ }
+ TheDriver.CCPrintHeadersFiltering = Filtering;
+ }
+ }
+
TheDriver.CCLogDiagnostics =
- CheckEnvVar("CC_LOG_DIAGNOSTICS", "CC_LOG_DIAGNOSTICS_FILE",
- TheDriver.CCLogDiagnosticsFilename);
+ checkEnvVar<bool>("CC_LOG_DIAGNOSTICS", "CC_LOG_DIAGNOSTICS_FILE",
+ TheDriver.CCLogDiagnosticsFilename);
TheDriver.CCPrintProcessStats =
- CheckEnvVar("CC_PRINT_PROC_STAT", "CC_PRINT_PROC_STAT_FILE",
- TheDriver.CCPrintStatReportFilename);
+ checkEnvVar<bool>("CC_PRINT_PROC_STAT", "CC_PRINT_PROC_STAT_FILE",
+ TheDriver.CCPrintStatReportFilename);
+
+ return true;
}
static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
@@ -278,27 +319,6 @@ static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
DiagClient->setPrefix(std::string(ExeBasename));
}
-// This lets us create the DiagnosticsEngine with a properly-filled-out
-// DiagnosticOptions instance.
-static DiagnosticOptions *
-CreateAndPopulateDiagOpts(ArrayRef<const char *> argv, bool &UseNewCC1Process) {
- auto *DiagOpts = new DiagnosticOptions;
- unsigned MissingArgIndex, MissingArgCount;
- InputArgList Args = getDriverOptTable().ParseArgs(
- argv.slice(1), MissingArgIndex, MissingArgCount);
- // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
- // Any errors that would be diagnosed here will also be diagnosed later,
- // when the DiagnosticsEngine actually exists.
- (void)ParseDiagnosticArgs(*DiagOpts, Args);
-
- UseNewCC1Process =
- Args.hasFlag(clang::driver::options::OPT_fno_integrated_cc1,
- clang::driver::options::OPT_fintegrated_cc1,
- /*Default=*/CLANG_SPAWN_CC1);
-
- return DiagOpts;
-}
-
static void SetInstallDir(SmallVectorImpl<const char *> &argv,
Driver &TheDriver, bool CanonicalPrefixes) {
// Attempt to find the original path used to invoke the driver, to determine
@@ -329,18 +349,19 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
llvm::cl::ResetAllOptionOccurrences();
llvm::BumpPtrAllocator A;
- llvm::StringSaver Saver(A);
- llvm::cl::ExpandResponseFiles(Saver, &llvm::cl::TokenizeGNUCommandLine, ArgV,
- /*MarkEOLs=*/false);
+ llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine);
+ if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) {
+ llvm::errs() << toString(std::move(Err)) << '\n';
+ return 1;
+ }
StringRef Tool = ArgV[1];
void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
if (Tool == "-cc1")
- return cc1_main(makeArrayRef(ArgV).slice(1), ArgV[0], GetExecutablePathVP);
+ return cc1_main(ArrayRef(ArgV).slice(1), ArgV[0], GetExecutablePathVP);
if (Tool == "-cc1as")
- return cc1as_main(makeArrayRef(ArgV).slice(2), ArgV[0],
- GetExecutablePathVP);
+ return cc1as_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP);
if (Tool == "-cc1gen-reproducer")
- return cc1gen_reproducer_main(makeArrayRef(ArgV).slice(2), ArgV[0],
+ return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0],
GetExecutablePathVP);
// Reject unknown tools.
llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
@@ -348,7 +369,7 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
return 1;
}
-int main(int Argc, const char **Argv) {
+int clang_main(int Argc, char **Argv) {
noteBottomOfStack();
llvm::InitLLVM X(Argc, Argv);
llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL
@@ -372,7 +393,7 @@ int main(int Argc, const char **Argv) {
// Finally, our -cc1 tools don't care which tokenization mode we use because
// response files written by clang will tokenize the same way in either mode.
bool ClangCLMode =
- IsClangCL(getDriverMode(Args[0], llvm::makeArrayRef(Args).slice(1)));
+ IsClangCL(getDriverMode(Args[0], llvm::ArrayRef(Args).slice(1)));
enum { Default, POSIX, Windows } RSPQuoting = Default;
for (const char *F : Args) {
if (strcmp(F, "--rsp-quoting=posix") == 0)
@@ -394,12 +415,17 @@ int main(int Argc, const char **Argv) {
if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).startswith("-cc1"))
MarkEOLs = false;
- llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Args, MarkEOLs);
+ llvm::cl::ExpansionContext ECtx(A, Tokenizer);
+ ECtx.setMarkEOLs(MarkEOLs);
+ if (llvm::Error Err = ECtx.expandResponseFiles(Args)) {
+ llvm::errs() << toString(std::move(Err)) << '\n';
+ return 1;
+ }
// Handle -cc1 integrated tools, even if -cc1 was expanded from a response
// file.
- auto FirstArg = std::find_if(Args.begin() + 1, Args.end(),
- [](const char *A) { return A != nullptr; });
+ auto FirstArg = llvm::find_if(llvm::drop_begin(Args),
+ [](const char *A) { return A != nullptr; });
if (FirstArg != Args.end() && StringRef(*FirstArg).startswith("-cc1")) {
// If -cc1 came from a response file, remove the EOL sentinels.
if (MarkEOLs) {
@@ -416,29 +442,29 @@ int main(int Argc, const char **Argv) {
// Skip end-of-line response file markers
if (Args[i] == nullptr)
continue;
- if (StringRef(Args[i]) == "-no-canonical-prefixes") {
+ if (StringRef(Args[i]) == "-canonical-prefixes")
+ CanonicalPrefixes = true;
+ else if (StringRef(Args[i]) == "-no-canonical-prefixes")
CanonicalPrefixes = false;
- break;
- }
}
// Handle CL and _CL_ which permits additional command line options to be
// prepended or appended.
if (ClangCLMode) {
// Arguments in "CL" are prepended.
- llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
- if (OptCL.hasValue()) {
+ std::optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
+ if (OptCL) {
SmallVector<const char *, 8> PrependedOpts;
- getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
+ getCLEnvVarOptions(*OptCL, Saver, PrependedOpts);
// Insert right after the program name to prepend to the argument list.
Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
}
// Arguments in "_CL_" are appended.
- llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
- if (Opt_CL_.hasValue()) {
+ std::optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
+ if (Opt_CL_) {
SmallVector<const char *, 8> AppendedOpts;
- getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
+ getCLEnvVarOptions(*Opt_CL_, Saver, AppendedOpts);
// Insert at the end of the argument list to append.
Args.append(AppendedOpts.begin(), AppendedOpts.end());
@@ -459,10 +485,15 @@ int main(int Argc, const char **Argv) {
// should spawn a new clang subprocess (old behavior).
// Not having an additional process saves some execution time of Windows,
// and makes debugging and profiling easier.
- bool UseNewCC1Process;
+ bool UseNewCC1Process = CLANG_SPAWN_CC1;
+ for (const char *Arg : Args)
+ UseNewCC1Process = llvm::StringSwitch<bool>(Arg)
+ .Case("-fno-integrated-cc1", true)
+ .Case("-fintegrated-cc1", false)
+ .Default(UseNewCC1Process);
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
- CreateAndPopulateDiagOpts(Args, UseNewCC1Process);
+ CreateAndPopulateDiagOpts(Args);
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
@@ -489,7 +520,8 @@ int main(int Argc, const char **Argv) {
insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings);
- SetBackdoorDriverOutputsFromEnvVars(TheDriver);
+ if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver))
+ return 1;
if (!UseNewCC1Process) {
TheDriver.CC1Main = &ExecuteCC1Tool;
@@ -498,32 +530,40 @@ int main(int Argc, const char **Argv) {
}
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args));
+
+ Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash;
+ if (Arg *A = C->getArgs().getLastArg(options::OPT_gen_reproducer_eq)) {
+ auto Level =
+ llvm::StringSwitch<std::optional<Driver::ReproLevel>>(A->getValue())
+ .Case("off", Driver::ReproLevel::Off)
+ .Case("crash", Driver::ReproLevel::OnCrash)
+ .Case("error", Driver::ReproLevel::OnError)
+ .Case("always", Driver::ReproLevel::Always)
+ .Default(std::nullopt);
+ if (!Level) {
+ llvm::errs() << "Unknown value for " << A->getSpelling() << ": '"
+ << A->getValue() << "'\n";
+ return 1;
+ }
+ ReproLevel = *Level;
+ }
+ if (!!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
+ ReproLevel = Driver::ReproLevel::Always;
+
int Res = 1;
bool IsCrash = false;
+ Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok;
+ // Pretend the first command failed if ReproStatus is Always.
+ const Command *FailingCommand = nullptr;
+ if (!C->getJobs().empty())
+ FailingCommand = &*C->getJobs().begin();
if (C && !C->containsError()) {
SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
- // Force a crash to test the diagnostics.
- if (TheDriver.GenReproducer) {
- Diags.Report(diag::err_drv_force_crash)
- << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
-
- // Pretend that every command failed.
- FailingCommands.clear();
- for (const auto &J : C->getJobs())
- if (const Command *C = dyn_cast<Command>(&J))
- FailingCommands.push_back(std::make_pair(-1, C));
-
- // Print the bug report message that would be printed if we did actually
- // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH.
- if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
- llvm::dbgs() << llvm::getBugReportMsg();
- }
-
for (const auto &P : FailingCommands) {
int CommandRes = P.first;
- const Command *FailingCommand = P.second;
+ FailingCommand = P.second;
if (!Res)
Res = CommandRes;
@@ -542,13 +582,22 @@ int main(int Argc, const char **Argv) {
// https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
IsCrash |= CommandRes > 128;
#endif
- if (IsCrash) {
- TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
+ CommandStatus =
+ IsCrash ? Driver::CommandStatus::Crash : Driver::CommandStatus::Error;
+ if (IsCrash)
break;
- }
}
}
+ // Print the bug report message that would be printed if we did actually
+ // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH.
+ if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
+ llvm::dbgs() << llvm::getBugReportMsg();
+ if (FailingCommand != nullptr &&
+ TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel,
+ *C, *FailingCommand))
+ Res = 1;
+
Diags.getClient()->finish();
if (!UseNewCC1Process && IsCrash) {
diff --git a/gnu/llvm/clang/tools/include-mapping/cppreference_parser.py b/gnu/llvm/clang/tools/include-mapping/cppreference_parser.py
new file mode 100644
index 00000000000..759269bffaa
--- /dev/null
+++ b/gnu/llvm/clang/tools/include-mapping/cppreference_parser.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+#===- cppreference_parser.py - ------------------------------*- python -*--===#
+#
+# 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
+#
+#===------------------------------------------------------------------------===#
+
+from bs4 import BeautifulSoup, NavigableString
+
+import collections
+import multiprocessing
+import os
+import re
+import signal
+import sys
+
+
+class Symbol:
+
+ def __init__(self, name, namespace, headers):
+ # unqualifed symbol name, e.g. "move"
+ self.name = name
+ # namespace of the symbol (with trailing "::"), e.g. "std::", "" (global scope)
+ # None for C symbols.
+ self.namespace = namespace
+ # a list of corresponding headers
+ self.headers = headers
+
+
+def _HasClass(tag, *classes):
+ for c in tag.get('class', []):
+ if c in classes:
+ return True
+ return False
+
+
+def _ParseSymbolPage(symbol_page_html, symbol_name):
+ """Parse symbol page and retrieve the include header defined in this page.
+ The symbol page provides header for the symbol, specifically in
+ "Defined in header <header>" section. An example:
+
+ <tr class="t-dsc-header">
+ <td colspan="2"> <div>Defined in header <code>&lt;ratio&gt;</code> </div>
+ </td></tr>
+
+ Returns a list of headers.
+ """
+ headers = set()
+ all_headers = set()
+
+ soup = BeautifulSoup(symbol_page_html, "html.parser")
+ # Rows in table are like:
+ # Defined in header <foo> .t-dsc-header
+ # Defined in header <bar> .t-dsc-header
+ # decl1 .t-dcl
+ # Defined in header <baz> .t-dsc-header
+ # decl2 .t-dcl
+ for table in soup.select('table.t-dcl-begin, table.t-dsc-begin'):
+ current_headers = []
+ was_decl = False
+ for row in table.select('tr'):
+ if _HasClass(row, 't-dcl', 't-dsc'):
+ was_decl = True
+ # Symbols are in the first cell.
+ found_symbols = row.find('td').stripped_strings
+ if not symbol_name in found_symbols:
+ continue
+ headers.update(current_headers)
+ elif _HasClass(row, 't-dsc-header'):
+ # If we saw a decl since the last header, this is a new block of headers
+ # for a new block of decls.
+ if was_decl:
+ current_headers = []
+ was_decl = False
+ # There are also .t-dsc-header for "defined in namespace".
+ if not "Defined in header " in row.text:
+ continue
+ # The interesting header content (e.g. <cstdlib>) is wrapped in <code>.
+ for header_code in row.find_all("code"):
+ current_headers.append(header_code.text)
+ all_headers.add(header_code.text)
+ # If the symbol was never named, consider all named headers.
+ return headers or all_headers
+
+
+def _ParseIndexPage(index_page_html):
+ """Parse index page.
+ The index page lists all std symbols and hrefs to their detailed pages
+ (which contain the defined header). An example:
+
+ <a href="abs.html" title="abs"><tt>abs()</tt></a> (int) <br>
+ <a href="acos.html" title="acos"><tt>acos()</tt></a> <br>
+
+ Returns a list of tuple (symbol_name, relative_path_to_symbol_page, variant).
+ """
+ symbols = []
+ soup = BeautifulSoup(index_page_html, "html.parser")
+ for symbol_href in soup.select("a[title]"):
+ # Ignore annotated symbols like "acos<>() (std::complex)".
+ # These tend to be overloads, and we the primary is more useful.
+ # This accidentally accepts begin/end despite the (iterator) caption: the
+ # (since C++11) note is first. They are good symbols, so the bug is unfixed.
+ caption = symbol_href.next_sibling
+ variant = None
+ if isinstance(caption, NavigableString) and "(" in caption:
+ variant = caption.text.strip(" ()")
+ symbol_tt = symbol_href.find("tt")
+ if symbol_tt:
+ symbols.append((symbol_tt.text.rstrip("<>()"), # strip any trailing <>()
+ symbol_href["href"], variant))
+ return symbols
+
+
+def _ReadSymbolPage(path, name):
+ with open(path) as f:
+ return _ParseSymbolPage(f.read(), name)
+
+
+def _GetSymbols(pool, root_dir, index_page_name, namespace, variants_to_accept):
+ """Get all symbols listed in the index page. All symbols should be in the
+ given namespace.
+
+ Returns a list of Symbols.
+ """
+
+ # Workflow steps:
+ # 1. Parse index page which lists all symbols to get symbol
+ # name (unqualified name) and its href link to the symbol page which
+ # contains the defined header.
+ # 2. Parse the symbol page to get the defined header.
+ index_page_path = os.path.join(root_dir, index_page_name)
+ with open(index_page_path, "r") as f:
+ # Read each symbol page in parallel.
+ results = [] # (symbol_name, promise of [header...])
+ for symbol_name, symbol_page_path, variant in _ParseIndexPage(f.read()):
+ # Variant symbols (e.g. the std::locale version of isalpha) add ambiguity.
+ # FIXME: use these as a fallback rather than ignoring entirely.
+ variants_for_symbol = variants_to_accept.get(
+ (namespace or "") + symbol_name, ())
+ if variant and variant not in variants_for_symbol:
+ continue
+ path = os.path.join(root_dir, symbol_page_path)
+ if os.path.isfile(path):
+ results.append((symbol_name,
+ pool.apply_async(_ReadSymbolPage, (path, symbol_name))))
+ else:
+ sys.stderr.write("Discarding information for symbol: %s. Page %s does not exist.\n"
+ % (symbol_name, path))
+
+ # Build map from symbol name to a set of headers.
+ symbol_headers = collections.defaultdict(set)
+ for symbol_name, lazy_headers in results:
+ symbol_headers[symbol_name].update(lazy_headers.get())
+
+ symbols = []
+ for name, headers in sorted(symbol_headers.items(), key=lambda t : t[0]):
+ symbols.append(Symbol(name, namespace, list(headers)))
+ return symbols
+
+
+def GetSymbols(parse_pages):
+ """Get all symbols by parsing the given pages.
+
+ Args:
+ parse_pages: a list of tuples (page_root_dir, index_page_name, namespace)
+ """
+ # By default we prefer the non-variant versions, as they're more common. But
+ # there are some symbols, whose variant is more common. This list describes
+ # those symbols.
+ variants_to_accept = {
+ # std::remove<> has variant algorithm.
+ "std::remove": ("algorithm"),
+ }
+ symbols = []
+ # Run many workers to process individual symbol pages under the symbol index.
+ # Don't allow workers to capture Ctrl-C.
+ pool = multiprocessing.Pool(
+ initializer=lambda: signal.signal(signal.SIGINT, signal.SIG_IGN))
+ try:
+ for root_dir, page_name, namespace in parse_pages:
+ symbols.extend(_GetSymbols(pool, root_dir, page_name, namespace,
+ variants_to_accept))
+ finally:
+ pool.terminate()
+ pool.join()
+ return symbols
diff --git a/gnu/llvm/clang/tools/include-mapping/gen_std.py b/gnu/llvm/clang/tools/include-mapping/gen_std.py
new file mode 100755
index 00000000000..db70771e0f5
--- /dev/null
+++ b/gnu/llvm/clang/tools/include-mapping/gen_std.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+#===- gen_std.py - ------------------------------------------*- python -*--===#
+#
+# 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
+#
+#===------------------------------------------------------------------------===#
+
+"""gen_std.py is a tool to generate a lookup table (from qualified names to
+include headers) for C/C++ Standard Library symbols by parsing archived HTML
+files from cppreference.
+
+The generated files are located in clang/include/Tooling/Inclusions.
+
+Caveats and FIXMEs:
+ - only symbols directly in "std" namespace are added, we should also add std's
+ subnamespace symbols (e.g. chrono).
+ - symbols with multiple variants or defined in multiple headers aren't added,
+ e.g. std::move, std::swap
+
+Usage:
+ 1. Install BeautifulSoup dependency, see instruction:
+ https://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-beautiful-soup
+ 2. Download cppreference offline HTML files (e.g. html_book_20181028.zip) at
+ https://en.cppreference.com/w/Cppreference:Archives
+ 3. Unzip the zip file from step 2 (e.g., to a "cppreference" directory). You should
+ get a "cppreference/reference" directory.
+ 4. Run the command:
+ // Generate C++ symbols
+ python3 gen_std.py -cppreference cppreference/reference -symbols=cpp > StdSymbolMap.inc
+ // Generate C++ removed symbols
+ python3 gen_std.py -cppreference cppreference/reference -symbols=cpp_removed > RemovedSymbolMap.inc
+ // Generate C symbols
+ python3 gen_std.py -cppreference cppreference/reference -symbols=c > CSymbolMap.inc
+"""
+
+
+import cppreference_parser
+import argparse
+import datetime
+import os
+import sys
+
+CODE_PREFIX = """\
+//===-- gen_std.py generated file -------------------------------*- C++ -*-===//
+//
+// Used to build a lookup table (qualified names => include headers) for %s
+// Standard Library symbols.
+//
+// This file was generated automatically by
+// clang/tools/include-mapping/gen_std.py, DO NOT EDIT!
+//
+// Generated from cppreference offline HTML book (modified on %s).
+//===----------------------------------------------------------------------===//
+"""
+
+def ParseArg():
+ parser = argparse.ArgumentParser(description='Generate StdGen file')
+ parser.add_argument('-cppreference', metavar='PATH',
+ default='',
+ help='path to the cppreference offline HTML directory',
+ required=True
+ )
+ parser.add_argument('-symbols',
+ default='cpp',
+ help='Generate c or cpp (removed) symbols. One of {cpp, c, cpp_removed}.',
+ required=True)
+ return parser.parse_args()
+
+
+def main():
+ args = ParseArg()
+ if args.symbols == 'cpp':
+ page_root = os.path.join(args.cppreference, "en", "cpp")
+ symbol_index_root = os.path.join(page_root, "symbol_index")
+ parse_pages = [
+ (page_root, "symbol_index.html", "std::"),
+ # std sub-namespace symbols have separated pages.
+ # We don't index std literal operators (e.g.
+ # std::literals::chrono_literals::operator""d), these symbols can't be
+ # accessed by std::<symbol_name>.
+ # FIXME: index std::placeholders symbols, placeholders.html page is
+ # different (which contains one entry for _1, _2, ..., _N), we need special
+ # handling.
+ (symbol_index_root, "chrono.html", "std::chrono::"),
+ (symbol_index_root, "filesystem.html", "std::filesystem::"),
+ (symbol_index_root, "pmr.html", "std::pmr::"),
+ (symbol_index_root, "regex_constants.html", "std::regex_constants::"),
+ (symbol_index_root, "this_thread.html", "std::this_thread::"),
+ ]
+ elif args.symbols == 'cpp_removed':
+ page_root = os.path.join(args.cppreference, "en", "cpp")
+ symbol_index_root = os.path.join(page_root, "symbol_index")
+ parse_pages = [(symbol_index_root, "zombie_names.html", "std::")]
+ elif args.symbols == 'c':
+ page_root = os.path.join(args.cppreference, "en", "c")
+ symbol_index_root = page_root
+ parse_pages = [(page_root, "index.html", None)]
+
+ if not os.path.exists(symbol_index_root):
+ exit("Path %s doesn't exist!" % symbol_index_root)
+
+ symbols = cppreference_parser.GetSymbols(parse_pages)
+
+ # We don't have version information from the unzipped offline HTML files.
+ # so we use the modified time of the symbol_index.html as the version.
+ index_page_path = os.path.join(page_root, "index.html")
+ cppreference_modified_date = datetime.datetime.fromtimestamp(
+ os.stat(index_page_path).st_mtime).strftime('%Y-%m-%d')
+ print(CODE_PREFIX % (args.symbols.upper(), cppreference_modified_date))
+ for symbol in symbols:
+ if len(symbol.headers) == 1:
+ # SYMBOL(unqualified_name, namespace, header)
+ print("SYMBOL(%s, %s, %s)" % (symbol.name, symbol.namespace,
+ symbol.headers[0]))
+ elif len(symbol.headers) == 0:
+ sys.stderr.write("No header found for symbol %s\n" % symbol.name)
+ else:
+ # FIXME: support symbols with multiple headers (e.g. std::move).
+ sys.stderr.write("Ambiguous header for symbol %s: %s\n" % (
+ symbol.name, ', '.join(symbol.headers)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/gnu/llvm/clang/tools/include-mapping/test.py b/gnu/llvm/clang/tools/include-mapping/test.py
new file mode 100755
index 00000000000..507e462e752
--- /dev/null
+++ b/gnu/llvm/clang/tools/include-mapping/test.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+#===- test.py - ---------------------------------------------*- python -*--===#
+#
+# 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
+#
+#===------------------------------------------------------------------------===#
+
+from cppreference_parser import _ParseSymbolPage, _ParseIndexPage
+
+import unittest
+
+class TestStdGen(unittest.TestCase):
+
+ def testParseIndexPage(self):
+ html = """
+ <a href="abs.html" title="abs"><tt>abs()</tt></a> (int) <br>
+ <a href="complex/abs.html" title="abs"><tt>abs&lt;&gt;()</tt></a> (std::complex) <br>
+ <a href="acos.html" title="acos"><tt>acos()</tt></a> <br>
+ <a href="acosh.html" title="acosh"><tt>acosh()</tt></a> <span class="t-mark-rev">(since C++11)</span> <br>
+ <a href="as_bytes.html" title="as bytes"><tt>as_bytes&lt;&gt;()</tt></a> <span class="t-mark-rev t-since-cxx20">(since C++20)</span> <br>
+ """
+
+ actual = _ParseIndexPage(html)
+ expected = [
+ ("abs", "abs.html", 'int'),
+ ("abs", "complex/abs.html", 'std::complex'),
+ ("acos", "acos.html", None),
+ ("acosh", "acosh.html", None),
+ ("as_bytes", "as_bytes.html", None),
+ ]
+ self.assertEqual(len(actual), len(expected))
+ for i in range(0, len(actual)):
+ self.assertEqual(expected[i][0], actual[i][0])
+ self.assertTrue(actual[i][1].endswith(expected[i][1]))
+ self.assertEqual(expected[i][2], actual[i][2])
+
+
+ def testParseSymbolPage_SingleHeader(self):
+ # Defined in header <cmath>
+ html = """
+ <table class="t-dcl-begin"><tbody>
+ <tr class="t-dsc-header">
+ <td> <div>Defined in header <code><a href="cmath.html" title="cmath">&lt;cmath&gt;</a></code>
+ </div></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr class="t-dcl">
+ <td>void foo()</td>
+ <td>this is matched</td>
+ </tr>
+</tbody></table>
+"""
+ self.assertEqual(_ParseSymbolPage(html, 'foo'), set(['<cmath>']))
+
+
+ def testParseSymbolPage_MulHeaders(self):
+ # Defined in header <cstddef>
+ # Defined in header <cstdio>
+ # Defined in header <cstdlib>
+ html = """
+<table class="t-dcl-begin"><tbody>
+ <tr class="t-dsc-header">
+ <td> <div>Defined in header <code><a href="cstddef.html" title="cstddef">&lt;cstddef&gt;</a></code>
+ </div></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr class="t-dcl">
+ <td>void bar()</td>
+ <td>this mentions foo, but isn't matched</td>
+ </tr>
+ <tr class="t-dsc-header">
+ <td> <div>Defined in header <code><a href="cstdio.html" title="cstdio">&lt;cstdio&gt;</a></code>
+ </div></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr class="t-dsc-header">
+ <td> <div>Defined in header <code><a href=".cstdlib.html" title="ccstdlib">&lt;cstdlib&gt;</a></code>
+ </div></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr class="t-dcl">
+ <td>
+ <span>void</span>
+ foo
+ <span>()</span>
+ </td>
+ <td>this is matched</td>
+ </tr>
+</tbody></table>
+"""
+ self.assertEqual(_ParseSymbolPage(html, "foo"),
+ set(['<cstdio>', '<cstdlib>']))
+
+
+ def testParseSymbolPage_MulHeadersInSameDiv(self):
+ # Multile <code> blocks in a Div.
+ # Defined in header <algorithm>
+ # Defined in header <utility>
+ html = """
+<table class="t-dcl-begin"><tbody>
+<tr class="t-dsc-header">
+<td><div>
+ Defined in header <code><a href="../header/algorithm.html" title="cpp/header/algorithm">&lt;algorithm&gt;</a></code><br>
+ Defined in header <code><a href="../header/utility.html" title="cpp/header/utility">&lt;utility&gt;</a></code>
+</div></td>
+<td></td>
+</tr>
+<tr class="t-dcl">
+ <td>
+ <span>void</span>
+ foo
+ <span>()</span>
+ </td>
+ <td>this is matched</td>
+</tr>
+</tbody></table>
+"""
+ self.assertEqual(_ParseSymbolPage(html, "foo"),
+ set(['<algorithm>', '<utility>']))
+
+ def testParseSymbolPage_MulSymbolsInSameTd(self):
+ # defined in header <cstdint>
+ # int8_t
+ # int16_t
+ html = """
+<table class="t-dcl-begin"><tbody>
+<tr class="t-dsc-header">
+<td><div>
+ Defined in header <code><a href="cstdint.html" title="cstdint">&lt;cstdint&gt;</a></code><br>
+</div></td>
+<td></td>
+</tr>
+<tr class="t-dcl">
+ <td>
+ <span>int8_t</span>
+ <span>int16_t</span>
+ </td>
+ <td>this is matched</td>
+</tr>
+</tbody></table>
+"""
+ self.assertEqual(_ParseSymbolPage(html, "int8_t"),
+ set(['<cstdint>']))
+ self.assertEqual(_ParseSymbolPage(html, "int16_t"),
+ set(['<cstdint>']))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/gnu/llvm/clang/tools/libclang/BuildSystem.cpp b/gnu/llvm/clang/tools/libclang/BuildSystem.cpp
index 0d69dcf1725..2f638ee8700 100644
--- a/gnu/llvm/clang/tools/libclang/BuildSystem.cpp
+++ b/gnu/llvm/clang/tools/libclang/BuildSystem.cpp
@@ -16,6 +16,7 @@
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemAlloc.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/gnu/llvm/clang/tools/libclang/CIndex.cpp b/gnu/llvm/clang/tools/libclang/CIndex.cpp
index 7b93164ccaa..15652c49934 100644
--- a/gnu/llvm/clang/tools/libclang/CIndex.cpp
+++ b/gnu/llvm/clang/tools/libclang/CIndex.cpp
@@ -39,7 +39,6 @@
#include "clang/Lex/Lexer.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/llvm-config.h"
@@ -57,6 +56,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/thread.h"
#include <mutex>
+#include <optional>
#if LLVM_ENABLE_THREADS != 0 && defined(__APPLE__)
#define USE_DARWIN_THREADS
@@ -535,10 +535,10 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
TLEnd = CXXUnit->top_level_end();
TL != TLEnd; ++TL) {
- const Optional<bool> V = handleDeclForVisitation(*TL);
- if (!V.hasValue())
+ const std::optional<bool> V = handleDeclForVisitation(*TL);
+ if (!V)
continue;
- return V.getValue();
+ return *V;
}
} else if (VisitDeclContext(
CXXUnit->getASTContext().getTranslationUnitDecl()))
@@ -600,16 +600,16 @@ bool CursorVisitor::VisitBlockDecl(BlockDecl *B) {
return false;
}
-Optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) {
+std::optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) {
if (RegionOfInterest.isValid()) {
SourceRange Range = getFullCursorExtent(Cursor, AU->getSourceManager());
if (Range.isInvalid())
- return None;
+ return std::nullopt;
switch (CompareRegionOfInterest(Range)) {
case RangeBefore:
// This declaration comes before the region of interest; skip it.
- return None;
+ return std::nullopt;
case RangeAfter:
// This declaration comes after the region of interest; we're done.
@@ -628,8 +628,8 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
// FIXME: Eventually remove. This part of a hack to support proper
// iteration over all Decls contained lexically within an ObjC container.
- SaveAndRestore<DeclContext::decl_iterator *> DI_saved(DI_current, &I);
- SaveAndRestore<DeclContext::decl_iterator> DE_saved(DE_current, E);
+ SaveAndRestore DI_saved(DI_current, &I);
+ SaveAndRestore DE_saved(DE_current, E);
for (; I != E; ++I) {
Decl *D = *I;
@@ -640,15 +640,15 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
if (auto *OMD = dyn_cast<ObjCMethodDecl>(D))
if (OMD->isSynthesizedAccessorStub())
continue;
- const Optional<bool> V = handleDeclForVisitation(D);
- if (!V.hasValue())
+ const std::optional<bool> V = handleDeclForVisitation(D);
+ if (!V)
continue;
- return V.getValue();
+ return *V;
}
return false;
}
-Optional<bool> CursorVisitor::handleDeclForVisitation(const Decl *D) {
+std::optional<bool> CursorVisitor::handleDeclForVisitation(const Decl *D) {
CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
// Ignore synthesized ivars here, otherwise if we have something like:
@@ -658,7 +658,7 @@ Optional<bool> CursorVisitor::handleDeclForVisitation(const Decl *D) {
// we passed the region-of-interest.
if (auto *ivarD = dyn_cast<ObjCIvarDecl>(D)) {
if (ivarD->getSynthesize())
- return None;
+ return std::nullopt;
}
// FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol
@@ -674,14 +674,14 @@ Optional<bool> CursorVisitor::handleDeclForVisitation(const Decl *D) {
Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU);
}
- const Optional<bool> V = shouldVisitCursor(Cursor);
- if (!V.hasValue())
- return None;
- if (!V.getValue())
+ const std::optional<bool> V = shouldVisitCursor(Cursor);
+ if (!V)
+ return std::nullopt;
+ if (!*V)
return false;
if (Visit(Cursor, true))
return true;
- return None;
+ return std::nullopt;
}
bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
@@ -761,10 +761,10 @@ bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl(
}
bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
- if (const auto *TC = D->getTypeConstraint())
- if (Visit(MakeCXCursor(TC->getImmediatelyDeclaredConstraint(), StmtParent,
- TU, RegionOfInterest)))
+ if (const auto *TC = D->getTypeConstraint()) {
+ if (VisitTypeConstraint(*TC))
return true;
+ }
// Visit the default argument.
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
@@ -863,6 +863,11 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// FIXME: Attributes?
}
+ if (auto *E = ND->getTrailingRequiresClause()) {
+ if (Visit(E))
+ return true;
+ }
+
if (ND->doesThisDeclarationHaveABody() && !ND->isLateTemplateParsed()) {
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) {
// Find the initializers that were written in the source.
@@ -1068,10 +1073,10 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
E = DeclsInContainer.end();
I != E; ++I) {
CXCursor Cursor = MakeCXCursor(*I, TU, RegionOfInterest);
- const Optional<bool> &V = shouldVisitCursor(Cursor);
- if (!V.hasValue())
+ const std::optional<bool> &V = shouldVisitCursor(Cursor);
+ if (!V)
continue;
- if (!V.getValue())
+ if (!*V)
return false;
if (Visit(Cursor, true))
return true;
@@ -1310,6 +1315,75 @@ bool CursorVisitor::VisitDecompositionDecl(DecompositionDecl *D) {
return VisitVarDecl(D);
}
+bool CursorVisitor::VisitConceptDecl(ConceptDecl *D) {
+ if (VisitTemplateParameters(D->getTemplateParameters()))
+ return true;
+
+ if (auto *E = D->getConstraintExpr()) {
+ if (Visit(MakeCXCursor(E, D, TU, RegionOfInterest)))
+ return true;
+ }
+ return false;
+}
+
+bool CursorVisitor::VisitTypeConstraint(const TypeConstraint &TC) {
+ if (TC.getNestedNameSpecifierLoc()) {
+ if (VisitNestedNameSpecifierLoc(TC.getNestedNameSpecifierLoc()))
+ return true;
+ }
+ if (TC.getNamedConcept()) {
+ if (Visit(MakeCursorTemplateRef(TC.getNamedConcept(),
+ TC.getConceptNameLoc(), TU)))
+ return true;
+ }
+ if (auto Args = TC.getTemplateArgsAsWritten()) {
+ for (const auto &Arg : Args->arguments()) {
+ if (VisitTemplateArgumentLoc(Arg))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CursorVisitor::VisitConceptRequirement(const concepts::Requirement &R) {
+ using namespace concepts;
+ switch (R.getKind()) {
+ case Requirement::RK_Type: {
+ const TypeRequirement &TR = cast<TypeRequirement>(R);
+ if (!TR.isSubstitutionFailure()) {
+ if (Visit(TR.getType()->getTypeLoc()))
+ return true;
+ }
+ break;
+ }
+ case Requirement::RK_Simple:
+ case Requirement::RK_Compound: {
+ const ExprRequirement &ER = cast<ExprRequirement>(R);
+ if (!ER.isExprSubstitutionFailure()) {
+ if (Visit(ER.getExpr()))
+ return true;
+ }
+ if (ER.getKind() == Requirement::RK_Compound) {
+ const auto &RTR = ER.getReturnTypeRequirement();
+ if (RTR.isTypeConstraint()) {
+ if (const auto *Cons = RTR.getTypeConstraint())
+ VisitTypeConstraint(*Cons);
+ }
+ }
+ break;
+ }
+ case Requirement::RK_Nested: {
+ const NestedRequirement &NR = cast<NestedRequirement>(R);
+ if (!NR.hasInvalidConstraint()) {
+ if (Visit(NR.getConstraintExpr()))
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
switch (Name.getName().getNameKind()) {
case clang::DeclarationName::Identifier:
@@ -1436,12 +1510,19 @@ bool CursorVisitor::VisitTemplateParameters(
return true;
}
+ if (const auto *E = Params->getRequiresClause()) {
+ if (Visit(MakeCXCursor(E, nullptr, TU, RegionOfInterest)))
+ return true;
+ }
+
return false;
}
bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) {
switch (Name.getKind()) {
case TemplateName::Template:
+ case TemplateName::UsingTemplate:
+ case TemplateName::QualifiedTemplate: // FIXME: Visit nested-name-specifier.
return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), Loc, TU));
case TemplateName::OverloadedTemplate:
@@ -1459,11 +1540,6 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) {
// FIXME: Visit nested-name-specifier.
return false;
- case TemplateName::QualifiedTemplate:
- // FIXME: Visit nested-name-specifier.
- return Visit(MakeCursorTemplateRef(
- Name.getAsQualifiedTemplateName()->getDecl(), Loc, TU));
-
case TemplateName::SubstTemplateTemplateParm:
return Visit(MakeCursorTemplateRef(
Name.getAsSubstTemplateTemplateParm()->getParameter(), Loc, TU));
@@ -1597,6 +1673,11 @@ bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) {
}
bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+ if (const auto *TC = TL.getDecl()->getTypeConstraint()) {
+ if (VisitTypeConstraint(*TC))
+ return true;
+ }
+
return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
}
@@ -1666,10 +1747,22 @@ bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
return Visit(TL.getPointeeLoc());
}
+bool CursorVisitor::VisitUsingTypeLoc(UsingTypeLoc TL) {
+ auto *underlyingDecl = TL.getUnderlyingType()->getAsTagDecl();
+ if (underlyingDecl) {
+ return Visit(MakeCursorTypeRef(underlyingDecl, TL.getNameLoc(), TU));
+ }
+ return false;
+}
+
bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
return Visit(TL.getModifiedLoc());
}
+bool CursorVisitor::VisitBTFTagAttributedTypeLoc(BTFTagAttributedTypeLoc TL) {
+ return Visit(TL.getWrappedLoc());
+}
+
bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL,
bool SkipResultType) {
if (!SkipResultType && Visit(TL.getReturnLoc()))
@@ -1730,7 +1823,7 @@ bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
}
bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo())
+ if (TypeSourceInfo *TSInfo = TL.getUnmodifiedTInfo())
return Visit(TSInfo->getTypeLoc());
return false;
@@ -1815,8 +1908,8 @@ DEFAULT_TYPELOC_IMPL(Enum, TagType)
DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParm, Type)
DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParmPack, Type)
DEFAULT_TYPELOC_IMPL(Auto, Type)
-DEFAULT_TYPELOC_IMPL(ExtInt, Type)
-DEFAULT_TYPELOC_IMPL(DependentExtInt, Type)
+DEFAULT_TYPELOC_IMPL(BitInt, Type)
+DEFAULT_TYPELOC_IMPL(DependentBitInt, Type)
bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) {
// Visit the nested-name-specifier, if present.
@@ -1866,6 +1959,9 @@ DEF_JOB(DeclRefExprParts, DeclRefExpr, DeclRefExprPartsKind)
DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind)
DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
+DEF_JOB(ConceptSpecializationExprVisit, ConceptSpecializationExpr,
+ ConceptSpecializationExprVisitKind)
+DEF_JOB(RequiresExprVisit, RequiresExpr, RequiresExprVisitKind)
DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind)
#undef DEF_JOB
@@ -2041,11 +2137,16 @@ public:
void VisitPseudoObjectExpr(const PseudoObjectExpr *E);
void VisitOpaqueValueExpr(const OpaqueValueExpr *E);
void VisitLambdaExpr(const LambdaExpr *E);
+ void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
+ void VisitRequiresExpr(const RequiresExpr *E);
+ void VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
void VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *D);
void VisitOMPLoopDirective(const OMPLoopDirective *D);
void VisitOMPParallelDirective(const OMPParallelDirective *D);
void VisitOMPSimdDirective(const OMPSimdDirective *D);
+ void
+ VisitOMPLoopTransformationDirective(const OMPLoopTransformationDirective *D);
void VisitOMPTileDirective(const OMPTileDirective *D);
void VisitOMPUnrollDirective(const OMPUnrollDirective *D);
void VisitOMPForDirective(const OMPForDirective *D);
@@ -2058,11 +2159,13 @@ public:
void VisitOMPParallelForDirective(const OMPParallelForDirective *D);
void VisitOMPParallelForSimdDirective(const OMPParallelForSimdDirective *D);
void VisitOMPParallelMasterDirective(const OMPParallelMasterDirective *D);
+ void VisitOMPParallelMaskedDirective(const OMPParallelMaskedDirective *D);
void VisitOMPParallelSectionsDirective(const OMPParallelSectionsDirective *D);
void VisitOMPTaskDirective(const OMPTaskDirective *D);
void VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *D);
void VisitOMPBarrierDirective(const OMPBarrierDirective *D);
void VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D);
+ void VisitOMPErrorDirective(const OMPErrorDirective *D);
void VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *D);
void
VisitOMPCancellationPointDirective(const OMPCancellationPointDirective *D);
@@ -2083,12 +2186,19 @@ public:
void VisitOMPTaskLoopDirective(const OMPTaskLoopDirective *D);
void VisitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective *D);
void VisitOMPMasterTaskLoopDirective(const OMPMasterTaskLoopDirective *D);
+ void VisitOMPMaskedTaskLoopDirective(const OMPMaskedTaskLoopDirective *D);
void
VisitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective *D);
+ void VisitOMPMaskedTaskLoopSimdDirective(
+ const OMPMaskedTaskLoopSimdDirective *D);
void VisitOMPParallelMasterTaskLoopDirective(
const OMPParallelMasterTaskLoopDirective *D);
+ void VisitOMPParallelMaskedTaskLoopDirective(
+ const OMPParallelMaskedTaskLoopDirective *D);
void VisitOMPParallelMasterTaskLoopSimdDirective(
const OMPParallelMasterTaskLoopSimdDirective *D);
+ void VisitOMPParallelMaskedTaskLoopSimdDirective(
+ const OMPParallelMaskedTaskLoopSimdDirective *D);
void VisitOMPDistributeDirective(const OMPDistributeDirective *D);
void VisitOMPDistributeParallelForDirective(
const OMPDistributeParallelForDirective *D);
@@ -2271,6 +2381,8 @@ void OMPClauseEnqueue::VisitOMPUpdateClause(const OMPUpdateClause *) {}
void OMPClauseEnqueue::VisitOMPCaptureClause(const OMPCaptureClause *) {}
+void OMPClauseEnqueue::VisitOMPCompareClause(const OMPCompareClause *) {}
+
void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
void OMPClauseEnqueue::VisitOMPAcqRelClause(const OMPAcqRelClause *) {}
@@ -2313,6 +2425,10 @@ void OMPClauseEnqueue::VisitOMPFilterClause(const OMPFilterClause *C) {
Visitor->AddStmt(C->getThreadID());
}
+void OMPClauseEnqueue::VisitOMPAlignClause(const OMPAlignClause *C) {
+ Visitor->AddStmt(C->getAlignment());
+}
+
void OMPClauseEnqueue::VisitOMPUnifiedAddressClause(
const OMPUnifiedAddressClause *) {}
@@ -2328,6 +2444,12 @@ void OMPClauseEnqueue::VisitOMPDynamicAllocatorsClause(
void OMPClauseEnqueue::VisitOMPAtomicDefaultMemOrderClause(
const OMPAtomicDefaultMemOrderClause *) {}
+void OMPClauseEnqueue::VisitOMPAtClause(const OMPAtClause *) {}
+
+void OMPClauseEnqueue::VisitOMPSeverityClause(const OMPSeverityClause *) {}
+
+void OMPClauseEnqueue::VisitOMPMessageClause(const OMPMessageClause *) {}
+
void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) {
Visitor->AddStmt(C->getDevice());
}
@@ -2559,6 +2681,10 @@ void OMPClauseEnqueue::VisitOMPIsDevicePtrClause(
const OMPIsDevicePtrClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseEnqueue::VisitOMPHasDeviceAddrClause(
+ const OMPHasDeviceAddrClause *C) {
+ VisitOMPClauseList(C);
+}
void OMPClauseEnqueue::VisitOMPNontemporalClause(
const OMPNontemporalClause *C) {
VisitOMPClauseList(C);
@@ -2579,6 +2705,13 @@ void OMPClauseEnqueue::VisitOMPAffinityClause(const OMPAffinityClause *C) {
for (const Expr *E : C->varlists())
Visitor->AddStmt(E);
}
+void OMPClauseEnqueue::VisitOMPBindClause(const OMPBindClause *C) {}
+void OMPClauseEnqueue::VisitOMPXDynCGroupMemClause(
+ const OMPXDynCGroupMemClause *C) {
+ VisitOMPClauseWithPreInit(C);
+ Visitor->AddStmt(C->getSize());
+}
+
} // namespace
void EnqueueVisitor::EnqueueChildren(const OMPClause *S) {
@@ -2628,7 +2761,7 @@ void EnqueueVisitor::VisitCXXNewExpr(const CXXNewExpr *E) {
// Enqueue the initializer , if any.
AddStmt(E->getInitializer());
// Enqueue the array size, if any.
- AddStmt(E->getArraySize().getValueOr(nullptr));
+ AddStmt(E->getArraySize().value_or(nullptr));
// Enqueue the allocated type.
AddTypeLoc(E->getAllocatedTypeSourceInfo());
// Enqueue the placement arguments.
@@ -2870,6 +3003,18 @@ void EnqueueVisitor::VisitLambdaExpr(const LambdaExpr *E) {
AddStmt(E->getBody());
WL.push_back(LambdaExprParts(E, Parent));
}
+void EnqueueVisitor::VisitConceptSpecializationExpr(
+ const ConceptSpecializationExpr *E) {
+ WL.push_back(ConceptSpecializationExprVisit(E, Parent));
+}
+void EnqueueVisitor::VisitRequiresExpr(const RequiresExpr *E) {
+ WL.push_back(RequiresExprVisit(E, Parent));
+ for (ParmVarDecl *VD : E->getLocalParameters())
+ AddDecl(VD);
+}
+void EnqueueVisitor::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E) {
+ EnqueueChildren(E);
+}
void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
// Treat the expression like its syntactic form.
Visit(E->getSyntacticForm());
@@ -2901,12 +3046,17 @@ void EnqueueVisitor::VisitOMPSimdDirective(const OMPSimdDirective *D) {
VisitOMPLoopDirective(D);
}
-void EnqueueVisitor::VisitOMPTileDirective(const OMPTileDirective *D) {
+void EnqueueVisitor::VisitOMPLoopTransformationDirective(
+ const OMPLoopTransformationDirective *D) {
VisitOMPLoopBasedDirective(D);
}
+void EnqueueVisitor::VisitOMPTileDirective(const OMPTileDirective *D) {
+ VisitOMPLoopTransformationDirective(D);
+}
+
void EnqueueVisitor::VisitOMPUnrollDirective(const OMPUnrollDirective *D) {
- VisitOMPLoopBasedDirective(D);
+ VisitOMPLoopTransformationDirective(D);
}
void EnqueueVisitor::VisitOMPForDirective(const OMPForDirective *D) {
@@ -2953,6 +3103,11 @@ void EnqueueVisitor::VisitOMPParallelMasterDirective(
VisitOMPExecutableDirective(D);
}
+void EnqueueVisitor::VisitOMPParallelMaskedDirective(
+ const OMPParallelMaskedDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
void EnqueueVisitor::VisitOMPParallelSectionsDirective(
const OMPParallelSectionsDirective *D) {
VisitOMPExecutableDirective(D);
@@ -2975,6 +3130,10 @@ void EnqueueVisitor::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D) {
VisitOMPExecutableDirective(D);
}
+void EnqueueVisitor::VisitOMPErrorDirective(const OMPErrorDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
void EnqueueVisitor::VisitOMPTaskgroupDirective(
const OMPTaskgroupDirective *D) {
VisitOMPExecutableDirective(D);
@@ -3058,21 +3217,41 @@ void EnqueueVisitor::VisitOMPMasterTaskLoopDirective(
VisitOMPLoopDirective(D);
}
+void EnqueueVisitor::VisitOMPMaskedTaskLoopDirective(
+ const OMPMaskedTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
void EnqueueVisitor::VisitOMPMasterTaskLoopSimdDirective(
const OMPMasterTaskLoopSimdDirective *D) {
VisitOMPLoopDirective(D);
}
+void EnqueueVisitor::VisitOMPMaskedTaskLoopSimdDirective(
+ const OMPMaskedTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
void EnqueueVisitor::VisitOMPParallelMasterTaskLoopDirective(
const OMPParallelMasterTaskLoopDirective *D) {
VisitOMPLoopDirective(D);
}
+void EnqueueVisitor::VisitOMPParallelMaskedTaskLoopDirective(
+ const OMPParallelMaskedTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
void EnqueueVisitor::VisitOMPParallelMasterTaskLoopSimdDirective(
const OMPParallelMasterTaskLoopSimdDirective *D) {
VisitOMPLoopDirective(D);
}
+void EnqueueVisitor::VisitOMPParallelMaskedTaskLoopSimdDirective(
+ const OMPParallelMaskedTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
void EnqueueVisitor::VisitOMPDistributeDirective(
const OMPDistributeDirective *D) {
VisitOMPLoopDirective(D);
@@ -3329,9 +3508,11 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
C != CEnd; ++C) {
if (!C->capturesVariable())
continue;
-
- if (Visit(MakeCursorVariableRef(C->getCapturedVar(), C->getLocation(),
- TU)))
+ // TODO: handle structured bindings here ?
+ if (!isa<VarDecl>(C->getCapturedVar()))
+ continue;
+ if (Visit(MakeCursorVariableRef(cast<VarDecl>(C->getCapturedVar()),
+ C->getLocation(), TU)))
return true;
}
// Visit init captures
@@ -3358,6 +3539,36 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
break;
}
+ case VisitorJob::ConceptSpecializationExprVisitKind: {
+ const ConceptSpecializationExpr *E =
+ cast<ConceptSpecializationExprVisit>(&LI)->get();
+ if (NestedNameSpecifierLoc QualifierLoc =
+ E->getNestedNameSpecifierLoc()) {
+ if (VisitNestedNameSpecifierLoc(QualifierLoc))
+ return true;
+ }
+
+ if (E->getNamedConcept() &&
+ Visit(MakeCursorTemplateRef(E->getNamedConcept(),
+ E->getConceptNameLoc(), TU)))
+ return true;
+
+ if (auto Args = E->getTemplateArgsAsWritten()) {
+ for (const auto &Arg : Args->arguments()) {
+ if (VisitTemplateArgumentLoc(Arg))
+ return true;
+ }
+ }
+ break;
+ }
+
+ case VisitorJob::RequiresExprVisitKind: {
+ const RequiresExpr *E = cast<RequiresExprVisit>(&LI)->get();
+ for (const concepts::Requirement *R : E->getRequirements())
+ VisitConceptRequirement(*R);
+ break;
+ }
+
case VisitorJob::PostChildrenVisitKind:
if (PostChildrenVisitor(Parent, ClientData))
return true;
@@ -3595,8 +3806,10 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
}
// Configure the diagnostics.
+ std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(
+ llvm::ArrayRef(command_line_args, num_command_line_args));
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- CompilerInstance::createDiagnostics(new DiagnosticOptions));
+ CompilerInstance::createDiagnostics(DiagOpts.release()));
if (options & CXTranslationUnit_KeepGoing)
Diags->setFatalsAsError(true);
@@ -3677,7 +3890,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
LibclangInvocationReporter InvocationReporter(
*CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation,
- options, llvm::makeArrayRef(*Args), /*InvocationArgs=*/None,
+ options, llvm::ArrayRef(*Args), /*InvocationArgs=*/std::nullopt,
unsaved_files);
std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCommandLine(
Args->data(), Args->data() + Args->size(),
@@ -3764,7 +3977,7 @@ enum CXErrorCode clang_parseTranslationUnit2FullArgv(
noteBottomOfStack();
result = clang_parseTranslationUnit_Impl(
CIdx, source_filename, command_line_args, num_command_line_args,
- llvm::makeArrayRef(unsaved_files, num_unsaved_files), options, out_TU);
+ llvm::ArrayRef(unsaved_files, num_unsaved_files), options, out_TU);
};
llvm::CrashRecoveryContext CRC;
@@ -3993,7 +4206,7 @@ static const ExprEvalResult *evaluateExpr(Expr *expr, CXCursor C) {
}
if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
- const ImplicitCastExpr *I = dyn_cast<ImplicitCastExpr>(expr);
+ const auto *I = cast<ImplicitCastExpr>(expr);
auto *subExpr = I->getSubExprAsWritten();
if (subExpr->getStmtClass() == Stmt::StringLiteralClass ||
subExpr->getStmtClass() == Stmt::ObjCStringLiteralClass) {
@@ -4295,7 +4508,7 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU,
CXErrorCode result;
auto ReparseTranslationUnitImpl = [=, &result]() {
result = clang_reparseTranslationUnit_Impl(
- TU, llvm::makeArrayRef(unsaved_files, num_unsaved_files), options);
+ TU, llvm::ArrayRef(unsaved_files, num_unsaved_files), options);
};
llvm::CrashRecoveryContext CRC;
@@ -4418,7 +4631,7 @@ const char *clang_getFileContents(CXTranslationUnit TU, CXFile file,
const SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
FileID fid = SM.translateFile(static_cast<FileEntry *>(file));
- llvm::Optional<llvm::MemoryBufferRef> buf = SM.getBufferOrNone(fid);
+ std::optional<llvm::MemoryBufferRef> buf = SM.getBufferOrNone(fid);
if (!buf) {
if (size)
*size = 0;
@@ -4932,7 +5145,7 @@ CXStringSet *clang_Cursor_getObjCManglings(CXCursor C) {
CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor C) {
if (clang_Cursor_isNull(C))
- return 0;
+ return nullptr;
return new PrintingPolicy(getCursorContext(C).getPrintingPolicy());
}
@@ -5379,6 +5592,12 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("ObjCMessageExpr");
case CXCursor_BuiltinBitCastExpr:
return cxstring::createRef("BuiltinBitCastExpr");
+ case CXCursor_ConceptSpecializationExpr:
+ return cxstring::createRef("ConceptSpecializationExpr");
+ case CXCursor_RequiresExpr:
+ return cxstring::createRef("RequiresExpr");
+ case CXCursor_CXXParenListInitExpr:
+ return cxstring::createRef("CXXParenListInitExpr");
case CXCursor_UnexposedStmt:
return cxstring::createRef("UnexposedStmt");
case CXCursor_DeclStmt:
@@ -5582,6 +5801,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("ModuleImport");
case CXCursor_OMPCanonicalLoop:
return cxstring::createRef("OMPCanonicalLoop");
+ case CXCursor_OMPMetaDirective:
+ return cxstring::createRef("OMPMetaDirective");
case CXCursor_OMPParallelDirective:
return cxstring::createRef("OMPParallelDirective");
case CXCursor_OMPSimdDirective:
@@ -5610,6 +5831,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPParallelForSimdDirective");
case CXCursor_OMPParallelMasterDirective:
return cxstring::createRef("OMPParallelMasterDirective");
+ case CXCursor_OMPParallelMaskedDirective:
+ return cxstring::createRef("OMPParallelMaskedDirective");
case CXCursor_OMPParallelSectionsDirective:
return cxstring::createRef("OMPParallelSectionsDirective");
case CXCursor_OMPTaskDirective:
@@ -5620,6 +5843,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPBarrierDirective");
case CXCursor_OMPTaskwaitDirective:
return cxstring::createRef("OMPTaskwaitDirective");
+ case CXCursor_OMPErrorDirective:
+ return cxstring::createRef("OMPErrorDirective");
case CXCursor_OMPTaskgroupDirective:
return cxstring::createRef("OMPTaskgroupDirective");
case CXCursor_OMPFlushDirective:
@@ -5658,12 +5883,20 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPTaskLoopSimdDirective");
case CXCursor_OMPMasterTaskLoopDirective:
return cxstring::createRef("OMPMasterTaskLoopDirective");
+ case CXCursor_OMPMaskedTaskLoopDirective:
+ return cxstring::createRef("OMPMaskedTaskLoopDirective");
case CXCursor_OMPMasterTaskLoopSimdDirective:
return cxstring::createRef("OMPMasterTaskLoopSimdDirective");
+ case CXCursor_OMPMaskedTaskLoopSimdDirective:
+ return cxstring::createRef("OMPMaskedTaskLoopSimdDirective");
case CXCursor_OMPParallelMasterTaskLoopDirective:
return cxstring::createRef("OMPParallelMasterTaskLoopDirective");
+ case CXCursor_OMPParallelMaskedTaskLoopDirective:
+ return cxstring::createRef("OMPParallelMaskedTaskLoopDirective");
case CXCursor_OMPParallelMasterTaskLoopSimdDirective:
return cxstring::createRef("OMPParallelMasterTaskLoopSimdDirective");
+ case CXCursor_OMPParallelMaskedTaskLoopSimdDirective:
+ return cxstring::createRef("OMPParallelMaskedTaskLoopSimdDirective");
case CXCursor_OMPDistributeDirective:
return cxstring::createRef("OMPDistributeDirective");
case CXCursor_OMPDistributeParallelForDirective:
@@ -5701,6 +5934,16 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPDispatchDirective");
case CXCursor_OMPMaskedDirective:
return cxstring::createRef("OMPMaskedDirective");
+ case CXCursor_OMPGenericLoopDirective:
+ return cxstring::createRef("OMPGenericLoopDirective");
+ case CXCursor_OMPTeamsGenericLoopDirective:
+ return cxstring::createRef("OMPTeamsGenericLoopDirective");
+ case CXCursor_OMPTargetTeamsGenericLoopDirective:
+ return cxstring::createRef("OMPTargetTeamsGenericLoopDirective");
+ case CXCursor_OMPParallelGenericLoopDirective:
+ return cxstring::createRef("OMPParallelGenericLoopDirective");
+ case CXCursor_OMPTargetParallelGenericLoopDirective:
+ return cxstring::createRef("OMPTargetParallelGenericLoopDirective");
case CXCursor_OverloadCandidate:
return cxstring::createRef("OverloadCandidate");
case CXCursor_TypeAliasTemplateDecl:
@@ -5717,6 +5960,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("attribute(warn_unused_result)");
case CXCursor_AlignedAttr:
return cxstring::createRef("attribute(aligned)");
+ case CXCursor_ConceptDecl:
+ return cxstring::createRef("ConceptDecl");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -6445,6 +6690,8 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Binding:
case Decl::MSProperty:
case Decl::MSGuid:
+ case Decl::HLSLBuffer:
+ case Decl::UnnamedGlobalConstant:
case Decl::TemplateParamObject:
case Decl::IndirectField:
case Decl::ObjCIvar:
@@ -6460,6 +6707,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Export:
case Decl::ObjCPropertyImpl:
case Decl::FileScopeAsm:
+ case Decl::TopLevelStmt:
case Decl::StaticAssert:
case Decl::Block:
case Decl::Captured:
@@ -6479,6 +6727,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::PragmaDetectMismatch:
case Decl::UsingPack:
case Decl::Concept:
+ case Decl::ImplicitConceptSpecialization:
case Decl::LifetimeExtendedTemporary:
case Decl::RequiresExprBody:
case Decl::UnresolvedUsingIfExists:
@@ -6719,8 +6968,8 @@ void clang_getDefinitionSpellingAndExtent(
CXCursor C, const char **startBuf, const char **endBuf, unsigned *startLine,
unsigned *startColumn, unsigned *endLine, unsigned *endColumn) {
assert(getCursorDecl(C) && "CXCursor has null decl");
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(getCursorDecl(C));
- CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody());
+ const auto *FD = cast<FunctionDecl>(getCursorDecl(C));
+ const auto *Body = cast<CompoundStmt>(FD->getBody());
SourceManager &SM = FD->getASTContext().getSourceManager();
*startBuf = SM.getCharacterData(Body->getLBracLoc());
@@ -6788,7 +7037,7 @@ void clang_enableStackTraces(void) {
void clang_executeOnThread(void (*fn)(void *), void *user_data,
unsigned stack_size) {
llvm::thread Thread(stack_size == 0 ? clang::DesiredStackSize
- : llvm::Optional<unsigned>(stack_size),
+ : std::optional<unsigned>(stack_size),
fn, user_data);
Thread.join();
}
@@ -6954,16 +7203,16 @@ CXToken *clang_getToken(CXTranslationUnit TU, CXSourceLocation Location) {
if (isNotUsableTU(TU)) {
LOG_BAD_TU(TU);
- return NULL;
+ return nullptr;
}
ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
if (!CXXUnit)
- return NULL;
+ return nullptr;
SourceLocation Begin = cxloc::translateSourceLocation(Location);
if (Begin.isInvalid())
- return NULL;
+ return nullptr;
SourceManager &SM = CXXUnit->getSourceManager();
std::pair<FileID, unsigned> DecomposedEnd = SM.getDecomposedLoc(Begin);
DecomposedEnd.second +=
@@ -6976,7 +7225,7 @@ CXToken *clang_getToken(CXTranslationUnit TU, CXSourceLocation Location) {
getTokens(CXXUnit, SourceRange(Begin, End), CXTokens);
if (CXTokens.empty())
- return NULL;
+ return nullptr;
CXTokens.resize(1);
CXToken *Token = static_cast<CXToken *>(llvm::safe_malloc(sizeof(CXToken)));
@@ -7159,7 +7408,7 @@ AnnotateTokensWorker::PostChildrenActions
AnnotateTokensWorker::DetermineChildActions(CXCursor Cursor) const {
PostChildrenActions actions;
- // The DeclRefExpr of CXXOperatorCallExpr refering to the custom operator is
+ // The DeclRefExpr of CXXOperatorCallExpr referring to the custom operator is
// visited before the arguments to the operator call. For the Call and
// Subscript operator the range of this DeclRefExpr includes the whole call
// expression, so that all tokens in that range would be mapped to the
@@ -7992,14 +8241,14 @@ static CXVersion convertVersion(VersionTuple In) {
Out.Major = In.getMajor();
- Optional<unsigned> Minor = In.getMinor();
- if (Minor.hasValue())
+ std::optional<unsigned> Minor = In.getMinor();
+ if (Minor)
Out.Minor = *Minor;
else
return Out;
- Optional<unsigned> Subminor = In.getSubminor();
- if (Subminor.hasValue())
+ std::optional<unsigned> Subminor = In.getSubminor();
+ if (Subminor)
Out.Subminor = *Subminor;
return Out;
@@ -8046,8 +8295,35 @@ static void getCursorPlatformAvailabilityForDecl(
deprecated_message, always_unavailable, unavailable_message,
AvailabilityAttrs);
- if (AvailabilityAttrs.empty())
+ // If no availability attributes are found, inherit the attribute from the
+ // containing decl or the class or category interface decl.
+ if (AvailabilityAttrs.empty()) {
+ const ObjCContainerDecl *CD = nullptr;
+ const DeclContext *DC = D->getDeclContext();
+
+ if (auto *IMD = dyn_cast<ObjCImplementationDecl>(D))
+ CD = IMD->getClassInterface();
+ else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D))
+ CD = CatD->getClassInterface();
+ else if (auto *IMD = dyn_cast<ObjCCategoryImplDecl>(D))
+ CD = IMD->getCategoryDecl();
+ else if (auto *ID = dyn_cast<ObjCInterfaceDecl>(DC))
+ CD = ID;
+ else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(DC))
+ CD = CatD;
+ else if (auto *IMD = dyn_cast<ObjCImplementationDecl>(DC))
+ CD = IMD->getClassInterface();
+ else if (auto *IMD = dyn_cast<ObjCCategoryImplDecl>(DC))
+ CD = IMD->getCategoryDecl();
+ else if (auto *PD = dyn_cast<ObjCProtocolDecl>(DC))
+ CD = PD;
+
+ if (CD)
+ getCursorPlatformAvailabilityForDecl(
+ CD, always_deprecated, deprecated_message, always_unavailable,
+ unavailable_message, AvailabilityAttrs);
return;
+ }
llvm::sort(
AvailabilityAttrs, [](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
@@ -8122,9 +8398,8 @@ int clang_getCursorPlatformAvailability(CXCursor cursor, int *always_deprecated,
getCursorPlatformAvailabilityForDecl(D, always_deprecated, deprecated_message,
always_unavailable, unavailable_message,
AvailabilityAttrs);
- for (const auto &Avail :
- llvm::enumerate(llvm::makeArrayRef(AvailabilityAttrs)
- .take_front(availability_size))) {
+ for (const auto &Avail : llvm::enumerate(
+ llvm::ArrayRef(AvailabilityAttrs).take_front(availability_size))) {
availability[Avail.index()].Platform =
cxstring::createDup(Avail.value()->getPlatform()->getName());
availability[Avail.index()].Introduced =
@@ -8260,7 +8535,8 @@ CXFile clang_getIncludedFile(CXCursor cursor) {
return nullptr;
const InclusionDirective *ID = getCursorInclusionDirective(cursor);
- return const_cast<FileEntry *>(ID->getFile());
+ OptionalFileEntryRef File = ID->getFile();
+ return const_cast<FileEntry *>(File ? &File->getFileEntry() : nullptr);
}
unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C, unsigned reserved) {
@@ -8268,7 +8544,7 @@ unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C, unsigned reserved) {
return CXObjCPropertyAttr_noattr;
unsigned Result = CXObjCPropertyAttr_noattr;
- const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(getCursorDecl(C));
+ const auto *PD = cast<ObjCPropertyDecl>(getCursorDecl(C));
ObjCPropertyAttribute::Kind Attr = PD->getPropertyAttributesAsWritten();
#define SET_CXOBJCPROP_ATTR(A) \
@@ -8296,7 +8572,7 @@ CXString clang_Cursor_getObjCPropertyGetterName(CXCursor C) {
if (C.kind != CXCursor_ObjCPropertyDecl)
return cxstring::createNull();
- const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(getCursorDecl(C));
+ const auto *PD = cast<ObjCPropertyDecl>(getCursorDecl(C));
Selector sel = PD->getGetterName();
if (sel.isNull())
return cxstring::createNull();
@@ -8308,7 +8584,7 @@ CXString clang_Cursor_getObjCPropertySetterName(CXCursor C) {
if (C.kind != CXCursor_ObjCPropertyDecl)
return cxstring::createNull();
- const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(getCursorDecl(C));
+ const auto *PD = cast<ObjCPropertyDecl>(getCursorDecl(C));
Selector sel = PD->getSetterName();
if (sel.isNull())
return cxstring::createNull();
@@ -8619,6 +8895,16 @@ unsigned clang_CXXMethod_isDefaulted(CXCursor C) {
return (Method && Method->isDefaulted()) ? 1 : 0;
}
+unsigned clang_CXXMethod_isDeleted(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const Decl *D = cxcursor::getCursorDecl(C);
+ const CXXMethodDecl *Method =
+ D ? dyn_cast_if_present<CXXMethodDecl>(D->getAsFunction()) : nullptr;
+ return (Method && Method->isDeleted()) ? 1 : 0;
+}
+
unsigned clang_CXXMethod_isStatic(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
@@ -8639,6 +8925,28 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) {
return (Method && Method->isVirtual()) ? 1 : 0;
}
+unsigned clang_CXXMethod_isCopyAssignmentOperator(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const Decl *D = cxcursor::getCursorDecl(C);
+ const CXXMethodDecl *Method =
+ D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr;
+
+ return (Method && Method->isCopyAssignmentOperator()) ? 1 : 0;
+}
+
+unsigned clang_CXXMethod_isMoveAssignmentOperator(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const Decl *D = cxcursor::getCursorDecl(C);
+ const CXXMethodDecl *Method =
+ D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr;
+
+ return (Method && Method->isMoveAssignmentOperator()) ? 1 : 0;
+}
+
unsigned clang_CXXRecord_isAbstract(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
@@ -8989,7 +9297,9 @@ void clang::setThreadBackgroundPriority() {
return;
#if LLVM_ENABLE_THREADS
- llvm::set_thread_priority(llvm::ThreadPriority::Background);
+ // The function name setThreadBackgroundPriority is for historical reasons;
+ // Low is more appropriate.
+ llvm::set_thread_priority(llvm::ThreadPriority::Low);
#endif
}
@@ -9078,7 +9388,7 @@ cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI, const Token &Tok,
return nullptr;
// Check that the identifier is not one of the macro arguments.
- if (std::find(MI->param_begin(), MI->param_end(), &II) != MI->param_end())
+ if (llvm::is_contained(MI->params(), &II))
return nullptr;
MacroDirective *InnerMD = PP.getLocalMacroDirectiveHistory(&II);
diff --git a/gnu/llvm/clang/tools/libclang/CIndexCodeCompletion.cpp b/gnu/llvm/clang/tools/libclang/CIndexCodeCompletion.cpp
index 68f35c41efd..d7df36dc7b8 100644
--- a/gnu/llvm/clang/tools/libclang/CIndexCodeCompletion.cpp
+++ b/gnu/llvm/clang/tools/libclang/CIndexCodeCompletion.cpp
@@ -541,6 +541,7 @@ static unsigned long long getContextsForContextKind(
case CodeCompletionContext::CCC_MacroName:
case CodeCompletionContext::CCC_PreprocessorExpression:
case CodeCompletionContext::CCC_PreprocessorDirective:
+ case CodeCompletionContext::CCC_Attribute:
case CodeCompletionContext::CCC_TypeQualifiers: {
//Only Clang results should be accepted, so we'll set all of the other
//context bits to 0 (i.e. the empty set)
@@ -655,14 +656,15 @@ namespace {
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates,
unsigned NumCandidates,
- SourceLocation OpenParLoc) override {
+ SourceLocation OpenParLoc,
+ bool Braced) override {
StoredResults.reserve(StoredResults.size() + NumCandidates);
for (unsigned I = 0; I != NumCandidates; ++I) {
- CodeCompletionString *StoredCompletion
- = Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(),
+ CodeCompletionString *StoredCompletion =
+ Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(),
getCodeCompletionTUInfo(),
- includeBriefComments());
-
+ includeBriefComments(), Braced);
+
CXCompletionResult R;
R.CursorKind = CXCursor_OverloadCandidate;
R.CompletionString = StoredCompletion;
@@ -867,7 +869,7 @@ CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU,
auto CodeCompleteAtImpl = [=, &result]() {
result = clang_codeCompleteAt_Impl(
TU, complete_filename, complete_line, complete_column,
- llvm::makeArrayRef(unsaved_files, num_unsaved_files), options);
+ llvm::ArrayRef(unsaved_files, num_unsaved_files), options);
};
llvm::CrashRecoveryContext CRC;
diff --git a/gnu/llvm/clang/tools/libclang/CIndexHigh.cpp b/gnu/llvm/clang/tools/libclang/CIndexHigh.cpp
index 04699ccb01a..0b49d1842e1 100644
--- a/gnu/llvm/clang/tools/libclang/CIndexHigh.cpp
+++ b/gnu/llvm/clang/tools/libclang/CIndexHigh.cpp
@@ -109,14 +109,14 @@ struct FindFileIdRefVisitData {
private:
bool isOverriddingMethod(const Decl *D) const {
- if (llvm::find(TopMethods, D) != TopMethods.end())
+ if (llvm::is_contained(TopMethods, D))
return true;
TopMethodsTy methods;
getTopOverriddenMethods(TU, D, methods);
for (TopMethodsTy::iterator
I = methods.begin(), E = methods.end(); I != E; ++I) {
- if (llvm::find(TopMethods, *I) != TopMethods.end())
+ if (llvm::is_contained(TopMethods, *I))
return true;
}
diff --git a/gnu/llvm/clang/tools/libclang/CIndexInclusionStack.cpp b/gnu/llvm/clang/tools/libclang/CIndexInclusionStack.cpp
index 3e05cff12c4..9cb9e18401f 100644
--- a/gnu/llvm/clang/tools/libclang/CIndexInclusionStack.cpp
+++ b/gnu/llvm/clang/tools/libclang/CIndexInclusionStack.cpp
@@ -59,8 +59,8 @@ void getInclusions(bool IsLocal, unsigned n, CXTranslationUnit TU,
// Callback to the client.
// FIXME: We should have a function to construct CXFiles.
- CB(static_cast<CXFile>(
- const_cast<FileEntry *>(FI.getContentCache().OrigEntry)),
+ CB(static_cast<CXFile>(const_cast<FileEntry *>(
+ static_cast<const FileEntry *>(FI.getContentCache().OrigEntry))),
InclusionStack.data(), InclusionStack.size(), clientData);
}
}
diff --git a/gnu/llvm/clang/tools/libclang/CIndexer.cpp b/gnu/llvm/clang/tools/libclang/CIndexer.cpp
index c7baab3a2c4..77da2e4fa5e 100644
--- a/gnu/llvm/clang/tools/libclang/CIndexer.cpp
+++ b/gnu/llvm/clang/tools/libclang/CIndexer.cpp
@@ -125,13 +125,23 @@ const std::string &CIndexer::getClangResourcesPath() {
#elif defined(_AIX)
getClangResourcesPathImplAIX(LibClangPath);
#else
- // This silly cast below avoids a C++ warning.
Dl_info info;
- if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
- llvm_unreachable("Call to dladdr() failed");
+ std::string Path;
+ // This silly cast below avoids a C++ warning.
+ if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) != 0) {
+ // We now have the CIndex directory, locate clang relative to it.
+ LibClangPath += info.dli_fname;
+ } else if (!(Path = llvm::sys::fs::getMainExecutable(nullptr, nullptr)).empty()) {
+ // If we can't get the path using dladdr, try to get the main executable
+ // path. This may be needed when we're statically linking libclang with
+ // musl libc, for example.
+ LibClangPath += Path;
+ } else {
+ // It's rather unlikely we end up here. But it could happen, so report an
+ // error instead of crashing.
+ llvm::report_fatal_error("could not locate Clang resource path");
+ }
- // We now have the CIndex directory, locate clang relative to it.
- LibClangPath += info.dli_fname;
#endif
// Cache our result.
@@ -166,7 +176,7 @@ LibclangInvocationReporter::LibclangInvocationReporter(
if (llvm::sys::fs::createUniqueFile(TempPath, FD, TempPath,
llvm::sys::fs::OF_Text))
return;
- File = std::string(TempPath.begin(), TempPath.end());
+ File = static_cast<std::string>(TempPath);
llvm::raw_fd_ostream OS(FD, /*ShouldClose=*/true);
// Write out the information about the invocation to it.
diff --git a/gnu/llvm/clang/tools/libclang/CMakeLists.txt b/gnu/llvm/clang/tools/libclang/CMakeLists.txt
index bf88dca0a34..4f23065a247 100644
--- a/gnu/llvm/clang/tools/libclang/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/libclang/CMakeLists.txt
@@ -2,7 +2,22 @@
# ABI, and when it is updated, it should be updated to the current
# LLVM_VERSION_MAJOR.
# Please also see clang/tools/libclang/libclang.map
-set(CLANG_SONAME 13)
+
+# This option defaults to CLANG_FORCE_MATCHING_LIBCLANG_SOVERSION
+# to ON - which means that it by default matches CLANG_VERSION_MAJOR
+#
+# TODO: This should probably not be a option going forward but we
+# we should commit to a way to do it. But due to getting this out
+# in LLVM 15.x we opted for a option.
+set(LIBCLANG_SOVERSION_ARG)
+if(NOT CLANG_FORCE_MATCHING_LIBCLANG_SOVERSION)
+ set(LIBCLANG_SOVERSION_ARG SOVERSION 13)
+endif()
+
+# TODO: harmonize usage of LIBCLANG_SOVERSION / LIBCLANG_LIBARY_VERSION
+# below; this was added under time-pressure to avoid reverting the
+# better default from LLVM 14 for LLVM 15.0.0-rc3, hence no time
+# to clean up previous inconsistencies.
set(SOURCES
ARCMigrate.cpp
@@ -17,6 +32,7 @@ set(SOURCES
CIndexer.cpp
CXComment.cpp
CXCursor.cpp
+ CXExtractAPI.cpp
CXIndexDataConsumer.cpp
CXCompilationDatabase.cpp
CXLoadedDiagnostic.cpp
@@ -45,6 +61,7 @@ set(LIBS
clangAST
clangBasic
clangDriver
+ clangExtractAPI
clangFrontend
clangIndex
clangLex
@@ -132,6 +149,7 @@ add_clang_library(libclang ${ENABLE_SHARED} ${ENABLE_STATIC} INSTALL_WITH_TOOLCH
${LLVM_TARGETS_TO_BUILD}
Core
Support
+ TargetParser
)
if(ENABLE_STATIC)
@@ -179,14 +197,14 @@ if(ENABLE_SHARED)
set_target_properties(libclang PROPERTIES
VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}${LLVM_VERSION_SUFFIX}
- SOVERSION ${CLANG_SONAME})
+ ${LIBCLANG_SOVERSION_ARG})
endif()
endif()
if(INTERNAL_INSTALL_PREFIX)
set(LIBCLANG_HEADERS_INSTALL_DESTINATION "${INTERNAL_INSTALL_PREFIX}/include")
else()
- set(LIBCLANG_HEADERS_INSTALL_DESTINATION include)
+ set(LIBCLANG_HEADERS_INSTALL_DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
endif()
install(DIRECTORY ../../include/clang-c
diff --git a/gnu/llvm/clang/tools/libclang/CXCursor.cpp b/gnu/llvm/clang/tools/libclang/CXCursor.cpp
index 6fb47300efb..d48063f105f 100644
--- a/gnu/llvm/clang/tools/libclang/CXCursor.cpp
+++ b/gnu/llvm/clang/tools/libclang/CXCursor.cpp
@@ -299,8 +299,6 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::BinaryConditionalOperatorClass:
case Stmt::TypeTraitExprClass:
case Stmt::CoawaitExprClass:
- case Stmt::ConceptSpecializationExprClass:
- case Stmt::RequiresExprClass:
case Stmt::DependentCoawaitExprClass:
case Stmt::CoyieldExprClass:
case Stmt::CXXBindTemporaryExprClass:
@@ -637,12 +635,27 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
return getSelectorIdentifierCursor(SelectorIdIndex, C);
}
+ case Stmt::ConceptSpecializationExprClass:
+ K = CXCursor_ConceptSpecializationExpr;
+ break;
+
+ case Stmt::RequiresExprClass:
+ K = CXCursor_RequiresExpr;
+ break;
+
+ case Stmt::CXXParenListInitExprClass:
+ K = CXCursor_CXXParenListInitExpr;
+ break;
+
case Stmt::MSDependentExistsStmtClass:
K = CXCursor_UnexposedStmt;
break;
case Stmt::OMPCanonicalLoopClass:
K = CXCursor_OMPCanonicalLoop;
break;
+ case Stmt::OMPMetaDirectiveClass:
+ K = CXCursor_OMPMetaDirective;
+ break;
case Stmt::OMPParallelDirectiveClass:
K = CXCursor_OMPParallelDirective;
break;
@@ -685,6 +698,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPParallelMasterDirectiveClass:
K = CXCursor_OMPParallelMasterDirective;
break;
+ case Stmt::OMPParallelMaskedDirectiveClass:
+ K = CXCursor_OMPParallelMaskedDirective;
+ break;
case Stmt::OMPParallelSectionsDirectiveClass:
K = CXCursor_OMPParallelSectionsDirective;
break;
@@ -700,6 +716,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPTaskwaitDirectiveClass:
K = CXCursor_OMPTaskwaitDirective;
break;
+ case Stmt::OMPErrorDirectiveClass:
+ K = CXCursor_OMPErrorDirective;
+ break;
case Stmt::OMPTaskgroupDirectiveClass:
K = CXCursor_OMPTaskgroupDirective;
break;
@@ -757,15 +776,27 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPMasterTaskLoopDirectiveClass:
K = CXCursor_OMPMasterTaskLoopDirective;
break;
+ case Stmt::OMPMaskedTaskLoopDirectiveClass:
+ K = CXCursor_OMPMaskedTaskLoopDirective;
+ break;
case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
K = CXCursor_OMPMasterTaskLoopSimdDirective;
break;
+ case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
+ K = CXCursor_OMPMaskedTaskLoopSimdDirective;
+ break;
case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
K = CXCursor_OMPParallelMasterTaskLoopDirective;
break;
+ case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
+ K = CXCursor_OMPParallelMaskedTaskLoopDirective;
+ break;
case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
K = CXCursor_OMPParallelMasterTaskLoopSimdDirective;
break;
+ case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
+ K = CXCursor_OMPParallelMaskedTaskLoopSimdDirective;
+ break;
case Stmt::OMPDistributeDirectiveClass:
K = CXCursor_OMPDistributeDirective;
break;
@@ -820,6 +851,21 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPMaskedDirectiveClass:
K = CXCursor_OMPMaskedDirective;
break;
+ case Stmt::OMPGenericLoopDirectiveClass:
+ K = CXCursor_OMPGenericLoopDirective;
+ break;
+ case Stmt::OMPTeamsGenericLoopDirectiveClass:
+ K = CXCursor_OMPTeamsGenericLoopDirective;
+ break;
+ case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
+ K = CXCursor_OMPTargetTeamsGenericLoopDirective;
+ break;
+ case Stmt::OMPParallelGenericLoopDirectiveClass:
+ K = CXCursor_OMPParallelGenericLoopDirective;
+ break;
+ case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
+ K = CXCursor_OMPTargetParallelGenericLoopDirective;
+ break;
case Stmt::BuiltinBitCastExprClass:
K = CXCursor_BuiltinBitCastExpr;
}
@@ -1314,34 +1360,43 @@ CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) {
}
int clang_Cursor_getNumTemplateArguments(CXCursor C) {
- if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+ CXCursorKind kind = clang_getCursorKind(C);
+ if (kind != CXCursor_FunctionDecl && kind != CXCursor_StructDecl &&
+ kind != CXCursor_ClassDecl &&
+ kind != CXCursor_ClassTemplatePartialSpecialization) {
return -1;
}
- const FunctionDecl *FD =
- llvm::dyn_cast_or_null<clang::FunctionDecl>(getCursorDecl(C));
- if (!FD) {
- return -1;
+ if (const auto *FD =
+ llvm::dyn_cast_if_present<clang::FunctionDecl>(getCursorDecl(C))) {
+ const FunctionTemplateSpecializationInfo *SpecInfo =
+ FD->getTemplateSpecializationInfo();
+ if (!SpecInfo) {
+ return -1;
+ }
+ return SpecInfo->TemplateArguments->size();
}
- const FunctionTemplateSpecializationInfo *SpecInfo =
- FD->getTemplateSpecializationInfo();
- if (!SpecInfo) {
- return -1;
+ if (const auto *SD =
+ llvm::dyn_cast_if_present<clang::ClassTemplateSpecializationDecl>(
+ getCursorDecl(C))) {
+ return SD->getTemplateArgs().size();
}
- return SpecInfo->TemplateArguments->size();
+ return -1;
}
enum CXGetTemplateArgumentStatus {
/** The operation completed successfully */
CXGetTemplateArgumentStatus_Success = 0,
- /** The specified cursor did not represent a FunctionDecl. */
- CXGetTemplateArgumentStatus_CursorNotFunctionDecl = -1,
+ /** The specified cursor did not represent a FunctionDecl or
+ ClassTemplateSpecializationDecl. */
+ CXGetTemplateArgumentStatus_CursorNotCompatibleDecl = -1,
- /** The specified cursor was not castable to a FunctionDecl. */
- CXGetTemplateArgumentStatus_BadFunctionDeclCast = -2,
+ /** The specified cursor was not castable to a FunctionDecl or
+ ClassTemplateSpecializationDecl. */
+ CXGetTemplateArgumentStatus_BadDeclCast = -2,
/** A NULL FunctionTemplateSpecializationInfo was retrieved. */
CXGetTemplateArgumentStatus_NullTemplSpecInfo = -3,
@@ -1352,28 +1407,42 @@ enum CXGetTemplateArgumentStatus {
static int clang_Cursor_getTemplateArgument(CXCursor C, unsigned I,
TemplateArgument *TA) {
- if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
- return CXGetTemplateArgumentStatus_CursorNotFunctionDecl;
+ CXCursorKind kind = clang_getCursorKind(C);
+ if (kind != CXCursor_FunctionDecl && kind != CXCursor_StructDecl &&
+ kind != CXCursor_ClassDecl &&
+ kind != CXCursor_ClassTemplatePartialSpecialization) {
+ return -1;
}
- const FunctionDecl *FD =
- llvm::dyn_cast_or_null<clang::FunctionDecl>(getCursorDecl(C));
- if (!FD) {
- return CXGetTemplateArgumentStatus_BadFunctionDeclCast;
- }
+ if (const auto *FD =
+ llvm::dyn_cast_if_present<clang::FunctionDecl>(getCursorDecl(C))) {
- const FunctionTemplateSpecializationInfo *SpecInfo =
- FD->getTemplateSpecializationInfo();
- if (!SpecInfo) {
- return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
+ const FunctionTemplateSpecializationInfo *SpecInfo =
+ FD->getTemplateSpecializationInfo();
+ if (!SpecInfo) {
+ return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
+ }
+
+ if (I >= SpecInfo->TemplateArguments->size()) {
+ return CXGetTemplateArgumentStatus_InvalidIndex;
+ }
+
+ *TA = SpecInfo->TemplateArguments->get(I);
+ return 0;
}
- if (I >= SpecInfo->TemplateArguments->size()) {
- return CXGetTemplateArgumentStatus_InvalidIndex;
+ if (const auto *SD =
+ llvm::dyn_cast_if_present<clang::ClassTemplateSpecializationDecl>(
+ getCursorDecl(C))) {
+ if (I >= SD->getTemplateArgs().size()) {
+ return CXGetTemplateArgumentStatus_InvalidIndex;
+ }
+
+ *TA = SD->getTemplateArgs()[I];
+ return 0;
}
- *TA = SpecInfo->TemplateArguments->get(I);
- return 0;
+ return CXGetTemplateArgumentStatus_BadDeclCast;
}
enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C,
@@ -1705,7 +1774,7 @@ CXType clang_Cursor_getReceiverType(CXCursor C) {
ME = dyn_cast_or_null<MemberExpr>(CE->getCallee());
if (ME) {
- if (dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl())) {
+ if (isa_and_nonnull<CXXMethodDecl>(ME->getMemberDecl())) {
auto receiverTy = ME->getBase()->IgnoreImpCasts()->getType();
return cxtype::MakeCXType(receiverTy, TU);
}
diff --git a/gnu/llvm/clang/tools/libclang/CXExtractAPI.cpp b/gnu/llvm/clang/tools/libclang/CXExtractAPI.cpp
new file mode 100644
index 00000000000..787334ab1bb
--- /dev/null
+++ b/gnu/llvm/clang/tools/libclang/CXExtractAPI.cpp
@@ -0,0 +1,151 @@
+//===- CXExtractAPI.cpp - libclang APIs for manipulating CXAPISet ---------===//
+//
+// 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 defines all libclang APIs related to manipulation CXAPISet
+//
+//===----------------------------------------------------------------------===//
+
+#include "CXCursor.h"
+#include "CXString.h"
+#include "CXTranslationUnit.h"
+#include "clang-c/CXErrorCode.h"
+#include "clang-c/Documentation.h"
+#include "clang-c/Index.h"
+#include "clang-c/Platform.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/ExtractAPIVisitor.h"
+#include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/CBindingWrapping.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::extractapi;
+
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(APISet, CXAPISet)
+
+static void WalkupFromMostDerivedType(ExtractAPIVisitor &Visitor, Decl *D);
+
+template <typename DeclTy>
+static bool WalkupParentContext(DeclContext *Parent,
+ ExtractAPIVisitor &Visitor) {
+ if (auto *D = dyn_cast<DeclTy>(Parent)) {
+ WalkupFromMostDerivedType(Visitor, D);
+ return true;
+ }
+ return false;
+}
+
+static void WalkupFromMostDerivedType(ExtractAPIVisitor &Visitor, Decl *D) {
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(DECL)
+#define DECL(CLASS, BASE) \
+ case Decl::CLASS: \
+ Visitor.WalkUpFrom##CLASS##Decl(static_cast<CLASS##Decl *>(D)); \
+ break;
+#include "clang/AST/DeclNodes.inc"
+ }
+
+ for (auto *Parent = D->getDeclContext(); Parent != nullptr;
+ Parent = Parent->getParent()) {
+ if (WalkupParentContext<ObjCContainerDecl>(Parent, Visitor))
+ return;
+ if (WalkupParentContext<TagDecl>(Parent, Visitor))
+ return;
+ }
+}
+
+static CXString GenerateCXStringFromSymbolGraphData(llvm::json::Object Obj) {
+ llvm::SmallString<0> BackingString;
+ llvm::raw_svector_ostream OS(BackingString);
+ OS << Value(std::move(Obj));
+ return cxstring::createDup(BackingString.str());
+}
+
+enum CXErrorCode clang_createAPISet(CXTranslationUnit tu, CXAPISet *out_api) {
+ if (cxtu::isNotUsableTU(tu) || !out_api)
+ return CXError_InvalidArguments;
+
+ ASTUnit *Unit = cxtu::getASTUnit(tu);
+
+ auto &Ctx = Unit->getASTContext();
+ auto Lang = Unit->getInputKind().getLanguage();
+ APISet *API = new APISet(Ctx.getTargetInfo().getTriple(), Lang,
+ Unit->getMainFileName().str());
+ ExtractAPIVisitor Visitor(
+ Ctx, [](SourceLocation Loc) { return true; }, *API);
+
+ for (auto It = Unit->top_level_begin(); It != Unit->top_level_end(); ++It) {
+ Visitor.TraverseDecl(*It);
+ }
+
+ *out_api = wrap(API);
+ return CXError_Success;
+}
+
+void clang_disposeAPISet(CXAPISet api) { delete unwrap(api); }
+
+CXString clang_getSymbolGraphForUSR(const char *usr, CXAPISet api) {
+ auto *API = unwrap(api);
+
+ if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(usr, *API))
+ return GenerateCXStringFromSymbolGraphData(std::move(*SGF));
+
+ return cxstring::createNull();
+}
+
+CXString clang_getSymbolGraphForCursor(CXCursor cursor) {
+ CXCursorKind Kind = clang_getCursorKind(cursor);
+ if (clang_isDeclaration(Kind)) {
+ const Decl *D = cxcursor::getCursorDecl(cursor);
+
+ if (!D)
+ return cxstring::createNull();
+
+ CXTranslationUnit TU = cxcursor::getCursorTU(cursor);
+ if (!TU)
+ return cxstring::createNull();
+
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
+
+ auto &Ctx = Unit->getASTContext();
+ auto Lang = Unit->getInputKind().getLanguage();
+ APISet API(Ctx.getTargetInfo().getTriple(), Lang,
+ Unit->getMainFileName().str());
+ ExtractAPIVisitor Visitor(
+ Ctx, [](SourceLocation Loc) { return true; }, API);
+
+ SmallString<128> USR;
+ if (index::generateUSRForDecl(D, USR))
+ return cxstring::createNull();
+
+ WalkupFromMostDerivedType(Visitor, const_cast<Decl *>(D));
+ auto *Record = API.findRecordForUSR(USR);
+
+ if (!Record)
+ return cxstring::createNull();
+
+ for (const auto &Fragment : Record->Declaration.getFragments()) {
+ if (Fragment.Declaration)
+ WalkupFromMostDerivedType(Visitor,
+ const_cast<Decl *>(Fragment.Declaration));
+ }
+
+ if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API))
+ return GenerateCXStringFromSymbolGraphData(std::move(*SGF));
+ }
+
+ return cxstring::createNull();
+}
diff --git a/gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.cpp b/gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.cpp
index 2f892fd1a43..da58a48001c 100644
--- a/gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.cpp
+++ b/gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.cpp
@@ -146,6 +146,11 @@ public:
DataConsumer.importedModule(D);
return true;
}
+
+ bool VisitConceptDecl(const ConceptDecl *D) {
+ DataConsumer.handleConcept(D);
+ return true;
+ }
};
CXSymbolRole getSymbolRole(SymbolRoleSet Role) {
@@ -458,21 +463,23 @@ void CXIndexDataConsumer::enteredMainFile(const FileEntry *File) {
}
void CXIndexDataConsumer::ppIncludedFile(SourceLocation hashLoc,
- StringRef filename,
- const FileEntry *File,
- bool isImport, bool isAngled,
- bool isModuleImport) {
+ StringRef filename,
+ OptionalFileEntryRef File,
+ bool isImport, bool isAngled,
+ bool isModuleImport) {
if (!CB.ppIncludedFile)
return;
+ const FileEntry *FE = File ? &File->getFileEntry() : nullptr;
+
ScratchAlloc SA(*this);
CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc),
SA.toCStr(filename),
static_cast<CXFile>(
- const_cast<FileEntry *>(File)),
+ const_cast<FileEntry *>(FE)),
isImport, isAngled, isModuleImport };
CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info);
- FileMap[File] = idxFile;
+ FileMap[FE] = idxFile;
}
void CXIndexDataConsumer::importedModule(const ImportDecl *ImportD) {
@@ -881,6 +888,12 @@ bool CXIndexDataConsumer::handleTypeAliasTemplate(const TypeAliasTemplateDecl *D
return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
}
+bool CXIndexDataConsumer::handleConcept(const ConceptDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(),
+ /*isDefinition=*/true, /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
bool CXIndexDataConsumer::handleReference(const NamedDecl *D, SourceLocation Loc,
CXCursor Cursor,
const NamedDecl *Parent,
@@ -1286,6 +1299,8 @@ static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage
case SymbolKind::Destructor: return CXIdxEntity_CXXDestructor;
case SymbolKind::ConversionFunction: return CXIdxEntity_CXXConversionFunction;
case SymbolKind::Parameter: return CXIdxEntity_Variable;
+ case SymbolKind::Concept:
+ return CXIdxEntity_CXXConcept;
}
llvm_unreachable("invalid symbol kind");
}
diff --git a/gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.h b/gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.h
index ace9d59bf04..b78ef367eea 100644
--- a/gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.h
+++ b/gnu/llvm/clang/tools/libclang/CXIndexDataConsumer.h
@@ -332,10 +332,9 @@ class CXIndexDataConsumer : public index::IndexDataConsumer {
public:
CXIndexDataConsumer(CXClientData clientData, IndexerCallbacks &indexCallbacks,
- unsigned indexOptions, CXTranslationUnit cxTU)
- : Ctx(nullptr), ClientData(clientData), CB(indexCallbacks),
- IndexOptions(indexOptions), CXTU(cxTU),
- StrScratch(), StrAdapterCount(0) { }
+ unsigned indexOptions, CXTranslationUnit cxTU)
+ : Ctx(nullptr), ClientData(clientData), CB(indexCallbacks),
+ IndexOptions(indexOptions), CXTU(cxTU), StrAdapterCount(0) {}
ASTContext &getASTContext() const { return *Ctx; }
CXTranslationUnit getCXTU() const { return CXTU; }
@@ -363,9 +362,9 @@ public:
void enteredMainFile(const FileEntry *File);
- void ppIncludedFile(SourceLocation hashLoc,
- StringRef filename, const FileEntry *File,
- bool isImport, bool isAngled, bool isModuleImport);
+ void ppIncludedFile(SourceLocation hashLoc, StringRef filename,
+ OptionalFileEntryRef File, bool isImport, bool isAngled,
+ bool isModuleImport);
void importedModule(const ImportDecl *ImportD);
void importedPCH(const FileEntry *File);
@@ -410,6 +409,8 @@ public:
bool handleFunctionTemplate(const FunctionTemplateDecl *D);
bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D);
+ bool handleConcept(const ConceptDecl *D);
+
bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor,
const NamedDecl *Parent,
const DeclContext *DC,
diff --git a/gnu/llvm/clang/tools/libclang/CXLoadedDiagnostic.cpp b/gnu/llvm/clang/tools/libclang/CXLoadedDiagnostic.cpp
index b3dcf977b92..bb6942a45f4 100644
--- a/gnu/llvm/clang/tools/libclang/CXLoadedDiagnostic.cpp
+++ b/gnu/llvm/clang/tools/libclang/CXLoadedDiagnostic.cpp
@@ -235,7 +235,7 @@ protected:
public:
DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
- : SerializedDiagnosticReader(), error(e), errorString(es) {
+ : error(e), errorString(es) {
if (error)
*error = CXLoadDiag_None;
if (errorString)
diff --git a/gnu/llvm/clang/tools/libclang/CXString.cpp b/gnu/llvm/clang/tools/libclang/CXString.cpp
index 2754795f4a6..5e427957a10 100644
--- a/gnu/llvm/clang/tools/libclang/CXString.cpp
+++ b/gnu/llvm/clang/tools/libclang/CXString.cpp
@@ -78,13 +78,22 @@ CXString createDup(const char *String) {
}
CXString createRef(StringRef String) {
+ if (!String.data())
+ return createNull();
+
+ // If the string is empty, it might point to a position in another string
+ // while having zero length. Make sure we don't create a reference to the
+ // larger string.
+ if (String.empty())
+ return createEmpty();
+
// If the string is not nul-terminated, we have to make a copy.
// FIXME: This is doing a one past end read, and should be removed! For memory
// we don't manage, the API string can become unterminated at any time outside
// our control.
- if (!String.empty() && String.data()[String.size()] != 0)
+ if (String.data()[String.size()] != 0)
return createDup(String);
CXString Result;
diff --git a/gnu/llvm/clang/tools/libclang/CXType.cpp b/gnu/llvm/clang/tools/libclang/CXType.cpp
index 0199c95b356..a833da374be 100644
--- a/gnu/llvm/clang/tools/libclang/CXType.cpp
+++ b/gnu/llvm/clang/tools/libclang/CXType.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Frontend/ASTUnit.h"
+#include <optional>
using namespace clang;
@@ -60,6 +61,7 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
BTCASE(ULongAccum);
BTCASE(Float16);
BTCASE(Float128);
+ BTCASE(Ibm128);
BTCASE(NullPtr);
BTCASE(Overload);
BTCASE(Dependent);
@@ -115,6 +117,7 @@ static CXTypeKind GetTypeKind(QualType T) {
TKCASE(Elaborated);
TKCASE(Pipe);
TKCASE(Attributed);
+ TKCASE(BTFTagAttributed);
TKCASE(Atomic);
default:
return CXType_Unexposed;
@@ -135,6 +138,10 @@ CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) {
return MakeCXType(ATT->getEquivalentType(), TU);
}
}
+ if (auto *ATT = T->getAs<BTFTagAttributedType>()) {
+ if (!(TU->ParsingOptions & CXTranslationUnit_IncludeAttributedTypes))
+ return MakeCXType(ATT->getWrappedType(), TU);
+ }
// Handle paren types as the original type
if (auto *PTT = T->getAs<ParenType>()) {
return MakeCXType(PTT->getInnerType(), TU);
@@ -174,7 +181,7 @@ static inline CXTranslationUnit GetTU(CXType CT) {
return static_cast<CXTranslationUnit>(CT.data[1]);
}
-static Optional<ArrayRef<TemplateArgument>>
+static std::optional<ArrayRef<TemplateArgument>>
GetTemplateArguments(QualType Type) {
assert(!Type.isNull());
if (const auto *Specialization = Type->getAs<TemplateSpecializationType>())
@@ -187,16 +194,17 @@ GetTemplateArguments(QualType Type) {
return TemplateDecl->getTemplateArgs().asArray();
}
- return None;
+ return std::nullopt;
}
-static Optional<QualType> TemplateArgumentToQualType(const TemplateArgument &A) {
+static std::optional<QualType>
+TemplateArgumentToQualType(const TemplateArgument &A) {
if (A.getKind() == TemplateArgument::Type)
return A.getAsType();
- return None;
+ return std::nullopt;
}
-static Optional<QualType>
+static std::optional<QualType>
FindTemplateArgumentTypeAt(ArrayRef<TemplateArgument> TA, unsigned index) {
unsigned current = 0;
for (const auto &A : TA) {
@@ -210,7 +218,7 @@ FindTemplateArgumentTypeAt(ArrayRef<TemplateArgument> TA, unsigned index) {
return TemplateArgumentToQualType(A);
current++;
}
- return None;
+ return std::nullopt;
}
CXType clang_getCursorType(CXCursor C) {
@@ -478,6 +486,14 @@ try_again:
return MakeCXType(T, GetTU(CT));
}
+CXType clang_getUnqualifiedType(CXType CT) {
+ return MakeCXType(GetQualType(CT).getUnqualifiedType(), GetTU(CT));
+}
+
+CXType clang_getNonReferenceType(CXType CT) {
+ return MakeCXType(GetQualType(CT).getNonReferenceType(), GetTU(CT));
+}
+
CXCursor clang_getTypeDeclaration(CXType CT) {
if (CT.kind == CXType_Invalid)
return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
@@ -577,6 +593,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(ULongAccum);
TKIND(Float16);
TKIND(Float128);
+ TKIND(Ibm128);
TKIND(NullPtr);
TKIND(Overload);
TKIND(Dependent);
@@ -608,6 +625,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(Elaborated);
TKIND(Pipe);
TKIND(Attributed);
+ TKIND(BTFTagAttributed);
TKIND(BFloat16);
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) TKIND(Id);
#include "clang/Basic/OpenCLImageTypes.def"
@@ -658,6 +676,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(X86RegCall);
TCALLINGCONV(X86VectorCall);
TCALLINGCONV(AArch64VectorCall);
+ TCALLINGCONV(AArch64SVEPCS);
TCALLINGCONV(Win64);
TCALLINGCONV(X86_64SysV);
TCALLINGCONV(AAPCS);
@@ -668,6 +687,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(PreserveMost);
TCALLINGCONV(PreserveAll);
case CC_SpirFunction: return CXCallingConv_Unexposed;
+ case CC_AMDGPUKernelCall: return CXCallingConv_Unexposed;
case CC_OpenCLKernel: return CXCallingConv_Unexposed;
break;
}
@@ -1049,6 +1069,9 @@ CXType clang_Type_getModifiedType(CXType CT) {
if (auto *ATT = T->getAs<AttributedType>())
return MakeCXType(ATT->getModifiedType(), GetTU(CT));
+ if (auto *ATT = T->getAs<BTFTagAttributedType>())
+ return MakeCXType(ATT->getWrappedType(), GetTU(CT));
+
return MakeCXType(QualType(), GetTU(CT));
}
@@ -1142,7 +1165,7 @@ int clang_Type_getNumTemplateArguments(CXType CT) {
if (!TA)
return -1;
- return GetTemplateArgumentArraySize(TA.getValue());
+ return GetTemplateArgumentArraySize(*TA);
}
CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned index) {
@@ -1154,8 +1177,8 @@ CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned index) {
if (!TA)
return MakeCXType(QualType(), GetTU(CT));
- Optional<QualType> QT = FindTemplateArgumentTypeAt(TA.getValue(), index);
- return MakeCXType(QT.getValueOr(QualType()), GetTU(CT));
+ std::optional<QualType> QT = FindTemplateArgumentTypeAt(*TA, index);
+ return MakeCXType(QT.value_or(QualType()), GetTU(CT));
}
CXType clang_Type_getObjCObjectBaseType(CXType CT) {
@@ -1309,8 +1332,7 @@ enum CXTypeNullabilityKind clang_Type_getNullability(CXType CT) {
if (T.isNull())
return CXTypeNullability_Invalid;
- ASTContext &Ctx = cxtu::getASTUnit(GetTU(CT))->getASTContext();
- if (auto nullability = T->getNullability(Ctx)) {
+ if (auto nullability = T->getNullability()) {
switch (*nullability) {
case NullabilityKind::NonNull:
return CXTypeNullability_NonNull;
diff --git a/gnu/llvm/clang/tools/libclang/CXType.h b/gnu/llvm/clang/tools/libclang/CXType.h
index 1d458086c09..ffe70a9b1c3 100644
--- a/gnu/llvm/clang/tools/libclang/CXType.h
+++ b/gnu/llvm/clang/tools/libclang/CXType.h
@@ -17,9 +17,6 @@
#include "clang/AST/Type.h"
namespace clang {
-
-class ASTUnit;
-
namespace cxtype {
CXType MakeCXType(QualType T, CXTranslationUnit TU);
diff --git a/gnu/llvm/clang/tools/libclang/CursorVisitor.h b/gnu/llvm/clang/tools/libclang/CursorVisitor.h
index 364d9fdebdb..2a9d7a7de16 100644
--- a/gnu/llvm/clang/tools/libclang/CursorVisitor.h
+++ b/gnu/llvm/clang/tools/libclang/CursorVisitor.h
@@ -14,11 +14,16 @@
#include "Index_Internal.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeLocVisitor.h"
+#include <optional>
namespace clang {
class PreprocessingRecord;
class ASTUnit;
+namespace concepts {
+class Requirement;
+}
+
namespace cxcursor {
class VisitorJob {
@@ -37,6 +42,8 @@ public:
MemberRefVisitKind,
SizeOfPackExprPartsKind,
LambdaExprPartsKind,
+ ConceptSpecializationExprVisitKind,
+ RequiresExprVisitKind,
PostChildrenVisitKind
};
@@ -201,7 +208,7 @@ public:
bool VisitAttributes(Decl *D);
bool VisitBlockDecl(BlockDecl *B);
bool VisitCXXRecordDecl(CXXRecordDecl *D);
- Optional<bool> shouldVisitCursor(CXCursor C);
+ std::optional<bool> shouldVisitCursor(CXCursor C);
bool VisitDeclContext(DeclContext *DC);
bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
bool VisitTypedefDecl(TypedefDecl *D);
@@ -242,6 +249,9 @@ public:
bool VisitStaticAssertDecl(StaticAssertDecl *D);
bool VisitFriendDecl(FriendDecl *D);
bool VisitDecompositionDecl(DecompositionDecl *D);
+ bool VisitConceptDecl(ConceptDecl *D);
+ bool VisitTypeConstraint(const TypeConstraint &TC);
+ bool VisitConceptRequirement(const concepts::Requirement &R);
// Name visitor
bool VisitDeclarationNameInfo(DeclarationNameInfo Name);
@@ -269,7 +279,7 @@ public:
LLVM_ATTRIBUTE_NOINLINE bool Visit(const Stmt *S);
private:
- Optional<bool> handleDeclForVisitation(const Decl *D);
+ std::optional<bool> handleDeclForVisitation(const Decl *D);
};
} // namespace cxcursor
diff --git a/gnu/llvm/clang/tools/libclang/FatalErrorHandler.cpp b/gnu/llvm/clang/tools/libclang/FatalErrorHandler.cpp
index ef21569637f..506b047c1b1 100644
--- a/gnu/llvm/clang/tools/libclang/FatalErrorHandler.cpp
+++ b/gnu/llvm/clang/tools/libclang/FatalErrorHandler.cpp
@@ -9,13 +9,14 @@
#include "clang-c/FatalErrorHandler.h"
#include "llvm/Support/ErrorHandling.h"
+#include <stdio.h>
#include <stdlib.h>
-static void aborting_fatal_error_handler(void *, const std::string &reason,
+static void aborting_fatal_error_handler(void *, const char *reason,
bool) {
// Write the result out to stderr avoiding errs() because raw_ostreams can
// call report_fatal_error.
- fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str());
+ fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason);
::abort();
}
diff --git a/gnu/llvm/clang/tools/libclang/Indexing.cpp b/gnu/llvm/clang/tools/libclang/Indexing.cpp
index 0e83ec6ca79..24ca98d4de4 100644
--- a/gnu/llvm/clang/tools/libclang/Indexing.cpp
+++ b/gnu/llvm/clang/tools/libclang/Indexing.cpp
@@ -261,9 +261,9 @@ public:
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
- CharSourceRange FilenameRange, const FileEntry *File,
- StringRef SearchPath, StringRef RelativePath,
- const Module *Imported,
+ CharSourceRange FilenameRange,
+ OptionalFileEntryRef File, StringRef SearchPath,
+ StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) override {
bool isImport = (IncludeTok.is(tok::identifier) &&
IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
@@ -508,8 +508,11 @@ static CXErrorCode clang_indexSourceFile_Impl(
if (source_filename)
Args->push_back(source_filename);
+ CreateInvocationOptions CIOpts;
+ CIOpts.Diags = Diags;
+ CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
std::shared_ptr<CompilerInvocation> CInvok =
- createInvocationFromCommandLine(*Args, Diags);
+ createInvocation(*Args, std::move(CIOpts));
if (!CInvok)
return CXError_Failure;
@@ -900,9 +903,8 @@ int clang_indexSourceFileFullArgv(
result = clang_indexSourceFile_Impl(
idxAction, client_data, index_callbacks, index_callbacks_size,
index_options, source_filename, command_line_args,
- num_command_line_args,
- llvm::makeArrayRef(unsaved_files, num_unsaved_files), out_TU,
- TU_options);
+ num_command_line_args, llvm::ArrayRef(unsaved_files, num_unsaved_files),
+ out_TU, TU_options);
};
llvm::CrashRecoveryContext CRC;
diff --git a/gnu/llvm/clang/tools/libclang/libclang.map b/gnu/llvm/clang/tools/libclang/libclang.map
index 716e2474966..e9818707185 100644
--- a/gnu/llvm/clang/tools/libclang/libclang.map
+++ b/gnu/llvm/clang/tools/libclang/libclang.map
@@ -405,6 +405,19 @@ LLVM_13 {
local: *;
};
+LLVM_16 {
+ global:
+ clang_getUnqualifiedType;
+ clang_getNonReferenceType;
+ clang_CXXMethod_isDeleted;
+ clang_CXXMethod_isCopyAssignmentOperator;
+ clang_CXXMethod_isMoveAssignmentOperator;
+ clang_createAPISet;
+ clang_disposeAPISet;
+ clang_getSymbolGraphForCursor;
+ clang_getSymbolGraphForUSR;
+};
+
# Example of how to add a new symbol version entry. If you do add a new symbol
# version, please update the example to depend on the version you added.
# LLVM_X {
diff --git a/gnu/llvm/clang/tools/nvptx-arch/CMakeLists.txt b/gnu/llvm/clang/tools/nvptx-arch/CMakeLists.txt
new file mode 100644
index 00000000000..9b31cdd772d
--- /dev/null
+++ b/gnu/llvm/clang/tools/nvptx-arch/CMakeLists.txt
@@ -0,0 +1,26 @@
+# //===--------------------------------------------------------------------===//
+# //
+# // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# // See https://llvm.org/LICENSE.txt for details.
+# // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+# //
+# //===--------------------------------------------------------------------===//
+
+set(LLVM_LINK_COMPONENTS Support)
+add_clang_tool(nvptx-arch NVPTXArch.cpp)
+
+# TODO: This is deprecated. Since CMake 3.17 we can use FindCUDAToolkit instead.
+find_package(CUDA QUIET)
+find_library(cuda-library NAMES cuda PATHS /lib64)
+if (NOT cuda-library AND CUDA_FOUND)
+ get_filename_component(CUDA_LIBDIR "${CUDA_cudart_static_LIBRARY}" DIRECTORY)
+ find_library(cuda-library NAMES cuda HINTS "${CUDA_LIBDIR}/stubs")
+endif()
+
+# If we found the CUDA library directly we just dynamically link against it.
+if (CUDA_FOUND AND cuda-library)
+ target_include_directories(nvptx-arch PRIVATE ${CUDA_INCLUDE_DIRS})
+ target_link_libraries(nvptx-arch PRIVATE ${cuda-library})
+else()
+ target_compile_definitions(nvptx-arch PRIVATE "DYNAMIC_CUDA")
+endif()
diff --git a/gnu/llvm/clang/tools/nvptx-arch/NVPTXArch.cpp b/gnu/llvm/clang/tools/nvptx-arch/NVPTXArch.cpp
new file mode 100644
index 00000000000..91723324c28
--- /dev/null
+++ b/gnu/llvm/clang/tools/nvptx-arch/NVPTXArch.cpp
@@ -0,0 +1,116 @@
+//===- NVPTXArch.cpp - list installed NVPTX devies ------*- C++ -*---------===//
+//
+// 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 implements a tool for detecting name of CUDA gpus installed in the
+// system.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <cstdio>
+#include <memory>
+
+#if DYNAMIC_CUDA
+typedef enum cudaError_enum {
+ CUDA_SUCCESS = 0,
+ CUDA_ERROR_NO_DEVICE = 100,
+} CUresult;
+
+typedef enum CUdevice_attribute_enum {
+ CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR = 75,
+ CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR = 76,
+} CUdevice_attribute;
+
+typedef uint32_t CUdevice;
+
+CUresult (*cuInit)(unsigned int);
+CUresult (*cuDeviceGetCount)(int *);
+CUresult (*cuGetErrorString)(CUresult, const char **);
+CUresult (*cuDeviceGet)(CUdevice *, int);
+CUresult (*cuDeviceGetAttribute)(int *, CUdevice_attribute, CUdevice);
+
+constexpr const char *DynamicCudaPath = "libcuda.so";
+
+llvm::Error loadCUDA() {
+ std::string ErrMsg;
+ auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
+ llvm::sys::DynamicLibrary::getPermanentLibrary(DynamicCudaPath, &ErrMsg));
+ if (!DynlibHandle->isValid()) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Failed to 'dlopen' %s", DynamicCudaPath);
+ }
+#define DYNAMIC_INIT(SYMBOL) \
+ { \
+ void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL); \
+ if (!SymbolPtr) \
+ return llvm::createStringError(llvm::inconvertibleErrorCode(), \
+ "Failed to 'dlsym' " #SYMBOL); \
+ SYMBOL = reinterpret_cast<decltype(SYMBOL)>(SymbolPtr); \
+ }
+ DYNAMIC_INIT(cuInit);
+ DYNAMIC_INIT(cuDeviceGetCount);
+ DYNAMIC_INIT(cuGetErrorString);
+ DYNAMIC_INIT(cuDeviceGet);
+ DYNAMIC_INIT(cuDeviceGetAttribute);
+#undef DYNAMIC_INIT
+ return llvm::Error::success();
+}
+#else
+
+#include "cuda.h"
+llvm::Error loadCUDA() { return llvm::Error::success(); }
+
+#endif
+
+static int handleError(CUresult Err) {
+ const char *ErrStr = nullptr;
+ CUresult Result = cuGetErrorString(Err, &ErrStr);
+ if (Result != CUDA_SUCCESS)
+ return 1;
+ fprintf(stderr, "CUDA error: %s\n", ErrStr);
+ return 1;
+}
+
+int main(int argc, char *argv[]) {
+ // Attempt to load the NVPTX driver runtime.
+ if (llvm::Error Err = loadCUDA()) {
+ logAllUnhandledErrors(std::move(Err), llvm::errs());
+ return 1;
+ }
+
+ if (CUresult Err = cuInit(0)) {
+ if (Err == CUDA_ERROR_NO_DEVICE)
+ return 0;
+ else
+ return handleError(Err);
+ }
+
+ int Count = 0;
+ if (CUresult Err = cuDeviceGetCount(&Count))
+ return handleError(Err);
+ if (Count == 0)
+ return 0;
+ for (int DeviceId = 0; DeviceId < Count; ++DeviceId) {
+ CUdevice Device;
+ if (CUresult Err = cuDeviceGet(&Device, DeviceId))
+ return handleError(Err);
+
+ int32_t Major, Minor;
+ if (CUresult Err = cuDeviceGetAttribute(
+ &Major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, Device))
+ return handleError(Err);
+ if (CUresult Err = cuDeviceGetAttribute(
+ &Minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, Device))
+ return handleError(Err);
+
+ printf("sm_%d%d\n", Major, Minor);
+ }
+ return 0;
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/CMakeLists.txt b/gnu/llvm/clang/tools/scan-build-py/CMakeLists.txt
index c9f1cb7d6b2..3aca22c0b0a 100644
--- a/gnu/llvm/clang/tools/scan-build-py/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/scan-build-py/CMakeLists.txt
@@ -43,7 +43,7 @@ foreach(BinFile ${BinFiles})
${CMAKE_BINARY_DIR}/bin/scan-build-py
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/scan-build)
install (PROGRAMS "bin/scan-build"
- DESTINATION bin
+ DESTINATION "${CMAKE_INSTALL_BINDIR}"
RENAME scan-build-py
COMPONENT scan-build-py)
list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/scan-build-py)
@@ -56,7 +56,7 @@ foreach(BinFile ${BinFiles})
${CMAKE_BINARY_DIR}/bin/
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile})
install(PROGRAMS bin/${BinFile}
- DESTINATION bin
+ DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT scan-build-py)
list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile})
endif()
@@ -72,7 +72,7 @@ foreach(lib ${LibExecs})
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${lib})
list(APPEND Depends ${CMAKE_BINARY_DIR}/libexec/${lib})
install(PROGRAMS libexec/${lib}
- DESTINATION libexec
+ DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}"
COMPONENT scan-build-py)
endforeach()
@@ -87,8 +87,8 @@ foreach(lib ${LibScanbuild})
${CMAKE_BINARY_DIR}/lib/libscanbuild/
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/${lib})
list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libscanbuild/${lib})
- install(PROGRAMS lib/libscanbuild/${lib}
- DESTINATION lib/libscanbuild
+ install(FILES lib/libscanbuild/${lib}
+ DESTINATION lib${CLANG_LIBDIR_SUFFIX}/libscanbuild
COMPONENT scan-build-py)
endforeach()
@@ -105,8 +105,8 @@ foreach(resource ${LibScanbuildResources})
${CMAKE_BINARY_DIR}/lib/libscanbuild/resources
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/resources/${resource})
list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources/${resource})
- install(PROGRAMS lib/libscanbuild/resources/${resource}
- DESTINATION lib/libscanbuild/resources
+ install(FILES lib/libscanbuild/resources/${resource}
+ DESTINATION lib${CLANG_LIBDIR_SUFFIX}/libscanbuild/resources
COMPONENT scan-build-py)
endforeach()
@@ -121,8 +121,8 @@ foreach(lib ${LibEar})
${CMAKE_BINARY_DIR}/lib/libear/
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libear/${lib})
list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libear/${lib})
- install(PROGRAMS lib/libear/${lib}
- DESTINATION lib/libear
+ install(FILES lib/libear/${lib}
+ DESTINATION lib${CLANG_LIBDIR_SUFFIX}/libear
COMPONENT scan-build-py)
endforeach()
diff --git a/gnu/llvm/clang/tools/scan-build-py/bin/analyze-build b/gnu/llvm/clang/tools/scan-build-py/bin/analyze-build
index b3f61429906..636b5aa4dd3 100755
--- a/gnu/llvm/clang/tools/scan-build-py/bin/analyze-build
+++ b/gnu/llvm/clang/tools/scan-build-py/bin/analyze-build
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
diff --git a/gnu/llvm/clang/tools/scan-build-py/bin/intercept-build b/gnu/llvm/clang/tools/scan-build-py/bin/intercept-build
index 9ecde399844..dcd0473ef54 100755
--- a/gnu/llvm/clang/tools/scan-build-py/bin/intercept-build
+++ b/gnu/llvm/clang/tools/scan-build-py/bin/intercept-build
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
diff --git a/gnu/llvm/clang/tools/scan-build-py/bin/scan-build b/gnu/llvm/clang/tools/scan-build-py/bin/scan-build
index a341751d993..3e5a5ade304 100755
--- a/gnu/llvm/clang/tools/scan-build-py/bin/scan-build
+++ b/gnu/llvm/clang/tools/scan-build-py/bin/scan-build
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
diff --git a/gnu/llvm/clang/tools/scan-build-py/lib/libear/ear.c b/gnu/llvm/clang/tools/scan-build-py/lib/libear/ear.c
index b06ec7ab000..323251181a4 100644
--- a/gnu/llvm/clang/tools/scan-build-py/lib/libear/ear.c
+++ b/gnu/llvm/clang/tools/scan-build-py/lib/libear/ear.c
@@ -411,6 +411,7 @@ static void bear_report_call(char const *fun, char const *const argv[]) {
const char *cwd = getcwd(NULL, 0);
if (0 == cwd) {
perror("bear: getcwd");
+ pthread_mutex_unlock(&mutex);
exit(EXIT_FAILURE);
}
char const *const out_dir = initial_env[0];
@@ -419,11 +420,13 @@ static void bear_report_call(char const *fun, char const *const argv[]) {
if (-1 ==
snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
perror("bear: snprintf");
+ pthread_mutex_unlock(&mutex);
exit(EXIT_FAILURE);
}
FILE *fd = fopen(filename, "a+");
if (0 == fd) {
perror("bear: fopen");
+ pthread_mutex_unlock(&mutex);
exit(EXIT_FAILURE);
}
fprintf(fd, "%d%c", getpid(), RS);
@@ -437,13 +440,14 @@ static void bear_report_call(char const *fun, char const *const argv[]) {
fprintf(fd, "%c", GS);
if (fclose(fd)) {
perror("bear: fclose");
+ pthread_mutex_unlock(&mutex);
exit(EXIT_FAILURE);
}
free((void *)cwd);
pthread_mutex_unlock(&mutex);
}
-/* update environment assure that chilren processes will copy the desired
+/* update environment assure that children processes will copy the desired
* behaviour */
static int bear_capture_env_t(bear_env_t *env) {
@@ -598,4 +602,4 @@ static void bear_strings_release(char const **in) {
free((void *)*it);
}
free((void *)in);
-} \ No newline at end of file
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/analyze.py b/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/analyze.py
index 9a249a8e15c..ebd6df1dc75 100644
--- a/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/analyze.py
+++ b/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/analyze.py
@@ -39,8 +39,10 @@ from libscanbuild.shell import decode
__all__ = ['scan_build', 'analyze_build', 'analyze_compiler_wrapper']
-COMPILER_WRAPPER_CC = 'analyze-cc'
-COMPILER_WRAPPER_CXX = 'analyze-c++'
+scanbuild_dir = os.path.dirname(os.path.realpath(__import__('sys').argv[0]))
+
+COMPILER_WRAPPER_CC = os.path.join(scanbuild_dir, '..', 'libexec', 'analyze-cc')
+COMPILER_WRAPPER_CXX = os.path.join(scanbuild_dir, '..', 'libexec', 'analyze-c++')
CTU_EXTDEF_MAP_FILENAME = 'externalDefMap.txt'
CTU_TEMP_DEFMAP_FOLDER = 'tmpExternalDefMaps'
@@ -355,6 +357,7 @@ def report_directory(hint, keep, output_format):
try:
yield name
finally:
+ args = (name,)
if os.listdir(name):
if output_format not in ['sarif', 'sarif-html']: # FIXME:
# 'scan-view' currently does not support sarif format.
@@ -362,6 +365,7 @@ def report_directory(hint, keep, output_format):
elif output_format == 'sarif-html':
msg = "Run 'scan-view %s' to examine bug reports or see " \
"merged sarif results at %s/results-merged.sarif."
+ args = (name, name)
else:
msg = "View merged sarif results at %s/results-merged.sarif."
keep = True
@@ -370,7 +374,7 @@ def report_directory(hint, keep, output_format):
msg = "Report directory '%s' contains no report, but kept."
else:
msg = "Removing directory '%s' because it contains no report."
- logging.warning(msg, name)
+ logging.warning(msg, *args)
if not keep:
os.rmdir(name)
@@ -382,8 +386,6 @@ def analyzer_params(args):
result = []
- if args.store_model:
- result.append('-analyzer-store={0}'.format(args.store_model))
if args.constraints_model:
result.append('-analyzer-constraints={0}'.format(
args.constraints_model))
diff --git a/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/report.py b/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/report.py
index 729b25e6350..0962b636a92 100644
--- a/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/report.py
+++ b/gnu/llvm/clang/tools/scan-build-py/lib/libscanbuild/report.py
@@ -417,7 +417,7 @@ def parse_bug_html(filename):
'bug_path_length': 1
}
- with open(filename) as handler:
+ with open(filename, encoding='utf-8') as handler:
for line in handler.readlines():
# do not read the file further
if endsign.match(line):
diff --git a/gnu/llvm/clang/tools/scan-build-py/libexec/analyze-c++ b/gnu/llvm/clang/tools/scan-build-py/libexec/analyze-c++
index a280b2fb4dd..5c72dfff4a8 100755
--- a/gnu/llvm/clang/tools/scan-build-py/libexec/analyze-c++
+++ b/gnu/llvm/clang/tools/scan-build-py/libexec/analyze-c++
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
diff --git a/gnu/llvm/clang/tools/scan-build-py/libexec/analyze-cc b/gnu/llvm/clang/tools/scan-build-py/libexec/analyze-cc
index 36bbcd93f98..fbdbde8f5b2 100755
--- a/gnu/llvm/clang/tools/scan-build-py/libexec/analyze-cc
+++ b/gnu/llvm/clang/tools/scan-build-py/libexec/analyze-cc
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
diff --git a/gnu/llvm/clang/tools/scan-build-py/libexec/intercept-c++ b/gnu/llvm/clang/tools/scan-build-py/libexec/intercept-c++
index 9e541a180d6..b8c8e923ec7 100755
--- a/gnu/llvm/clang/tools/scan-build-py/libexec/intercept-c++
+++ b/gnu/llvm/clang/tools/scan-build-py/libexec/intercept-c++
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
diff --git a/gnu/llvm/clang/tools/scan-build-py/libexec/intercept-cc b/gnu/llvm/clang/tools/scan-build-py/libexec/intercept-cc
index 9e541a180d6..b8c8e923ec7 100755
--- a/gnu/llvm/clang/tools/scan-build-py/libexec/intercept-cc
+++ b/gnu/llvm/clang/tools/scan-build-py/libexec/intercept-cc
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
diff --git a/gnu/llvm/clang/tools/scan-build/CMakeLists.txt b/gnu/llvm/clang/tools/scan-build/CMakeLists.txt
index ec0702d76f1..ef687b0e90a 100644
--- a/gnu/llvm/clang/tools/scan-build/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/scan-build/CMakeLists.txt
@@ -47,7 +47,7 @@ if(CLANG_INSTALL_SCANBUILD)
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile})
list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile})
install(PROGRAMS bin/${BinFile}
- DESTINATION bin
+ DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT scan-build)
endforeach()
@@ -61,21 +61,21 @@ if(CLANG_INSTALL_SCANBUILD)
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${LibexecFile})
list(APPEND Depends ${CMAKE_BINARY_DIR}/libexec/${LibexecFile})
install(PROGRAMS libexec/${LibexecFile}
- DESTINATION libexec
+ DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}"
COMPONENT scan-build)
endforeach()
foreach(ManPage ${ManPages})
- add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage}
+ add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage}"
COMMAND ${CMAKE_COMMAND} -E make_directory
- ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1
+ "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1"
COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage}
- ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/
+ "${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage}"
+ "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage})
- list(APPEND Depends ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage})
- install(PROGRAMS man/${ManPage}
- DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
+ list(APPEND Depends "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage}")
+ install(FILES man/${ManPage}
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man1"
COMPONENT scan-build)
endforeach()
@@ -89,7 +89,7 @@ if(CLANG_INSTALL_SCANBUILD)
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/share/scan-build/${ShareFile})
list(APPEND Depends ${CMAKE_BINARY_DIR}/share/scan-build/${ShareFile})
install(FILES share/scan-build/${ShareFile}
- DESTINATION share/scan-build
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/scan-build"
COMPONENT scan-build)
endforeach()
diff --git a/gnu/llvm/clang/tools/scan-build/bin/scan-build b/gnu/llvm/clang/tools/scan-build/bin/scan-build
index 645f5507b6f..8cd525f054f 100755
--- a/gnu/llvm/clang/tools/scan-build/bin/scan-build
+++ b/gnu/llvm/clang/tools/scan-build/bin/scan-build
@@ -14,7 +14,6 @@
use strict;
use warnings;
use FindBin qw($RealBin);
-use Digest::MD5;
use File::Basename;
use File::Find;
use File::Copy qw(copy);
@@ -62,7 +61,6 @@ my %Options = (
UseCC => undef, # C compiler to use for compilation.
UseCXX => undef, # C++ compiler to use for compilation.
AnalyzerTarget => undef,
- StoreModel => undef,
ConstraintsModel => undef,
InternalStats => undef,
OutputFormat => "html",
@@ -269,27 +267,6 @@ sub SetHtmlEnv {
}
##----------------------------------------------------------------------------##
-# ComputeDigest - Compute a digest of the specified file.
-##----------------------------------------------------------------------------##
-
-sub ComputeDigest {
- my $FName = shift;
- DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);
-
- # Use Digest::MD5. We don't have to be cryptographically secure. We're
- # just looking for duplicate files that come from a non-malicious source.
- # We use Digest::MD5 because it is a standard Perl module that should
- # come bundled on most systems.
- open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
- binmode FILE;
- my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
- close(FILE);
-
- # Return the digest.
- return $Result;
-}
-
-##----------------------------------------------------------------------------##
# UpdatePrefix - Compute the common prefix of files.
##----------------------------------------------------------------------------##
@@ -374,8 +351,6 @@ sub AddStatLine {
# Sometimes a source file is scanned more than once, and thus produces
# multiple error reports. We use a cache to solve this problem.
-my %AlreadyScanned;
-
sub ScanFile {
my $Index = shift;
@@ -383,19 +358,6 @@ sub ScanFile {
my $FName = shift;
my $Stats = shift;
- # Compute a digest for the report file. Determine if we have already
- # scanned a file that looks just like it.
-
- my $digest = ComputeDigest("$Dir/$FName");
-
- if (defined $AlreadyScanned{$digest}) {
- # Redundant file. Remove it.
- unlink("$Dir/$FName");
- return;
- }
-
- $AlreadyScanned{$digest} = 1;
-
# At this point the report file is not world readable. Make it happen.
chmod(0644, "$Dir/$FName");
@@ -1014,8 +976,7 @@ sub SetEnv {
die "$var is undefined\n" if (!defined $var);
$ENV{$var} = $EnvVars->{$var};
}
- foreach my $var ('CCC_ANALYZER_STORE_MODEL',
- 'CCC_ANALYZER_CONSTRAINTS_MODEL',
+ foreach my $var ('CCC_ANALYZER_CONSTRAINTS_MODEL',
'CCC_ANALYZER_INTERNAL_STATS',
'CCC_ANALYZER_OUTPUT_FORMAT',
'CCC_CC',
@@ -1741,12 +1702,6 @@ sub ProcessArgs {
next;
}
- if ($arg eq "-store") {
- shift @$Args;
- $Options{StoreModel} = shift @$Args;
- next;
- }
-
if ($arg eq "-constraints") {
shift @$Args;
$Options{ConstraintsModel} = shift @$Args;
@@ -1995,7 +1950,6 @@ my %EnvVars = (
'CCC_CC' => $Options{UseCC},
'CCC_CXX' => $Options{UseCXX},
'CCC_REPORT_FAILURES' => $Options{ReportFailures},
- 'CCC_ANALYZER_STORE_MODEL' => $Options{StoreModel},
'CCC_ANALYZER_CONSTRAINTS_MODEL' => $Options{ConstraintsModel},
'CCC_ANALYZER_INTERNAL_STATS' => $Options{InternalStats},
'CCC_ANALYZER_OUTPUT_FORMAT' => $Options{OutputFormat},
diff --git a/gnu/llvm/clang/tools/scan-build/libexec/ccc-analyzer b/gnu/llvm/clang/tools/scan-build/libexec/ccc-analyzer
index ed0d4d3d73f..0c900293956 100755
--- a/gnu/llvm/clang/tools/scan-build/libexec/ccc-analyzer
+++ b/gnu/llvm/clang/tools/scan-build/libexec/ccc-analyzer
@@ -72,7 +72,7 @@ my $AnalyzerTarget;
# If on OSX, use xcrun to determine the SDK root.
my $UseXCRUN = 0;
-if (`uname -a` =~ m/Darwin/) {
+if (`uname -s` =~ m/Darwin/) {
$DefaultCCompiler = 'clang';
$DefaultCXXCompiler = 'clang++';
# Older versions of OSX do not have xcrun to
@@ -80,7 +80,7 @@ if (`uname -a` =~ m/Darwin/) {
if (-x "/usr/bin/xcrun") {
$UseXCRUN = 1;
}
-} elsif (`uname -a` =~ m/OpenBSD/) {
+} elsif (`uname -s` =~ m/(FreeBSD|OpenBSD)/) {
$DefaultCCompiler = 'cc';
$DefaultCXXCompiler = 'c++';
} else {
@@ -466,9 +466,6 @@ my $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'};
# Get the plugins to load.
my $Plugins = $ENV{'CCC_ANALYZER_PLUGINS'};
-# Get the store model.
-my $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'};
-
# Get the constraints engine.
my $ConstraintsModel = $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'};
@@ -729,10 +726,6 @@ if ($Action eq 'compile' or $Action eq 'link') {
push @CmdArgs, '-x', $FileLang;
}
- if (defined $StoreModel) {
- push @AnalyzeArgs, "-analyzer-store=$StoreModel";
- }
-
if (defined $ConstraintsModel) {
push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel";
}
diff --git a/gnu/llvm/clang/tools/scan-build/man/scan-build.1 b/gnu/llvm/clang/tools/scan-build/man/scan-build.1
index 4f3cd8d1033..10593dc1cd9 100644
--- a/gnu/llvm/clang/tools/scan-build/man/scan-build.1
+++ b/gnu/llvm/clang/tools/scan-build/man/scan-build.1
@@ -2,9 +2,9 @@
.\" See https://llvm.org/LICENSE.txt for license information.
.\" SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
.\" $Id$
-.Dd May 25, 2012
+.Dd Aug 1, 2022
.Dt SCAN-BUILD 1
-.Os "clang" "3.5"
+.Os "clang" "16"
.Sh NAME
.Nm scan-build
.Nd Clang static analyzer
@@ -110,7 +110,7 @@ increases verbosity.
.It Fl V , Fl Fl view
View analysis results in a web browser when the build completes.
.It Fl constraints Op Ar model
-Specify the contraint engine used by the analyzer. By default the
+Specify the constraint engine used by the analyzer. By default the
.Ql range
model is used. Specifying
.Ql basic
diff --git a/gnu/llvm/clang/tools/scan-view/CMakeLists.txt b/gnu/llvm/clang/tools/scan-view/CMakeLists.txt
index eccc6b83195..07aec76ee66 100644
--- a/gnu/llvm/clang/tools/scan-view/CMakeLists.txt
+++ b/gnu/llvm/clang/tools/scan-view/CMakeLists.txt
@@ -20,7 +20,7 @@ if(CLANG_INSTALL_SCANVIEW)
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile})
list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile})
install(PROGRAMS bin/${BinFile}
- DESTINATION bin
+ DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT scan-view)
endforeach()
@@ -34,7 +34,7 @@ if(CLANG_INSTALL_SCANVIEW)
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/share/${ShareFile})
list(APPEND Depends ${CMAKE_BINARY_DIR}/share/scan-view/${ShareFile})
install(FILES share/${ShareFile}
- DESTINATION share/scan-view
+ DESTINATION "${CMAKE_INSTALL_DATADIR}/scan-view"
COMPONENT scan-view)
endforeach()