diff options
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/.clang-format | 20 | ||||
| -rw-r--r-- | backend/.clang-tidy | 49 | ||||
| -rw-r--r-- | backend/CMakeLists.txt | 85 | ||||
| -rw-r--r-- | backend/cmake/RCCBackendConfig.cmake.in | 7 | ||||
| -rw-r--r-- | backend/cmake/modules/RCCBackendBuild.cmake | 93 | ||||
| -rw-r--r-- | backend/cmake/modules/RCCBackendDeveloperTools.cmake | 50 | ||||
| -rw-r--r-- | backend/include/rcc/Support/Error.h | 49 | ||||
| -rw-r--r-- | backend/lib/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | backend/lib/Support/CMakeLists.txt | 40 | ||||
| -rw-r--r-- | backend/lib/Support/Error.cpp | 28 | ||||
| -rw-r--r-- | backend/unittests/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | backend/unittests/Support/CMakeLists.txt | 16 | ||||
| -rw-r--r-- | backend/unittests/Support/ErrorTest.cpp | 33 |
13 files changed, 476 insertions, 0 deletions
diff --git a/backend/.clang-format b/backend/.clang-format new file mode 100644 index 0000000..fc4f3fc --- /dev/null +++ b/backend/.clang-format @@ -0,0 +1,20 @@ +BasedOnStyle: LLVM +Language: Cpp +Standard: Latest +ColumnLimit: 100 +IndentWidth: 2 +ContinuationIndentWidth: 4 +UseTab: Never +BreakBeforeBraces: Attach +PointerAlignment: Right +ReferenceAlignment: Pointer +DerivePointerAlignment: false +NamespaceIndentation: None +FixNamespaceComments: true +SortIncludes: CaseSensitive +IncludeBlocks: Regroup +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +LineEnding: LF diff --git a/backend/.clang-tidy b/backend/.clang-tidy new file mode 100644 index 0000000..a0e18ce --- /dev/null +++ b/backend/.clang-tidy @@ -0,0 +1,49 @@ +HeaderFilterRegex: '(^|/)(include|lib|tools|utils|unittests)/' +WarningsAsErrors: '' +FormatStyle: file +Checks: > + -*, + clang-diagnostic-*, + bugprone-*, + -bugprone-easily-swappable-parameters, + performance-*, + portability-*, + llvm-header-guard, + llvm-namespace-comment, + llvm-qualified-auto, + misc-definitions-in-headers, + misc-misplaced-const, + misc-new-delete-overloads, + misc-non-copyable-objects, + modernize-use-default-member-init, + modernize-use-equals-default, + modernize-use-equals-delete, + modernize-use-nullptr, + modernize-use-override, + readability-container-size-empty, + readability-identifier-naming, + readability-redundant-*, + readability-simplify-boolean-expr + +CheckOptions: + - { key: readability-identifier-naming.NamespaceCase, value: lower_case } + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.StructCase, value: CamelCase } + - { key: readability-identifier-naming.UnionCase, value: CamelCase } + - { key: readability-identifier-naming.EnumCase, value: CamelCase } + - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } + - { key: readability-identifier-naming.TypedefCase, value: CamelCase } + - { key: readability-identifier-naming.TypeTemplateParameterCase, value: CamelCase } + - { key: readability-identifier-naming.FunctionCase, value: camelBack } + - { key: readability-identifier-naming.MethodCase, value: camelBack } + - { key: readability-identifier-naming.VariableCase, value: CamelCase } + - { key: readability-identifier-naming.ParameterCase, value: CamelCase } + - { key: readability-identifier-naming.MemberCase, value: CamelCase } + - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } + - { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase } + - { key: readability-identifier-naming.ClassConstantCase, value: CamelCase } + - { key: readability-identifier-naming.EnumConstantCase, value: CamelCase } + - { key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE } + - { key: readability-identifier-naming.IgnoreMainLikeFunctions, value: 1 } + - { key: readability-redundant-member-init.IgnoreBaseInCopyConstructors, value: 1 } + - { key: modernize-use-default-member-init.UseAssignment, value: 1 } diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt new file mode 100644 index 0000000..2d5cc82 --- /dev/null +++ b/backend/CMakeLists.txt @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +cmake_minimum_required(VERSION 3.25) + +set(RCC_BACKEND_VERSION 0.1.0) +set(RCC_BACKEND_IS_STANDALONE OFF) +set(RCC_BACKEND_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +set(RCC_BACKEND_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project( + RCCBackend + VERSION ${RCC_BACKEND_VERSION} + DESCRIPTION "Independent RCC machine-code backend" + LANGUAGES CXX + ) + set(RCC_BACKEND_IS_STANDALONE ON) + include(CTest) +endif() + +if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") + message( + FATAL_ERROR + "RCC Backend must be compiled with Clang; found '${CMAKE_CXX_COMPILER_ID}'" + ) +endif() + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message( + FATAL_ERROR + "RCC Backend does not support in-source builds. Configure a separate build directory." + ) +endif() + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) +include(RCCBackendBuild) +include(RCCBackendDeveloperTools) + +option(RCC_BACKEND_BUILD_TESTS "Build RCC Backend tests" "${BUILD_TESTING}") +option(RCC_BACKEND_WARNINGS_AS_ERRORS "Treat compiler warnings as errors" OFF) +option(RCC_BACKEND_ENABLE_CLANG_TIDY "Run clang-tidy during each compilation" OFF) + +rcc_backend_initialize_toolchain() + +add_subdirectory(lib) + +if(RCC_BACKEND_BUILD_TESTS) + enable_testing() + add_subdirectory(unittests) +endif() + +rcc_backend_add_developer_targets() + +install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/RCCBackendConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/RCCBackendConfig.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/RCCBackend" +) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/RCCBackendConfigVersion.cmake" + VERSION "${RCC_BACKEND_VERSION}" + COMPATIBILITY SameMajorVersion +) + +install( + EXPORT RCCBackendTargets + FILE RCCBackendTargets.cmake + NAMESPACE RCCBackend:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/RCCBackend" +) + +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/RCCBackendConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/RCCBackendConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/RCCBackend" +) diff --git a/backend/cmake/RCCBackendConfig.cmake.in b/backend/cmake/RCCBackendConfig.cmake.in new file mode 100644 index 0000000..910572b --- /dev/null +++ b/backend/cmake/RCCBackendConfig.cmake.in @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/RCCBackendTargets.cmake") + +check_required_components(RCCBackend) diff --git a/backend/cmake/modules/RCCBackendBuild.cmake b/backend/cmake/modules/RCCBackendBuild.cmake new file mode 100644 index 0000000..79e7bb1 --- /dev/null +++ b/backend/cmake/modules/RCCBackendBuild.cmake @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +function(rcc_backend_initialize_toolchain) + string(REGEX MATCH "^[0-9]+" RCCBackendClangMajor "${CMAKE_CXX_COMPILER_VERSION}") + + find_program( + RCC_BACKEND_CLANG_FORMAT + NAMES "clang-format-${RCCBackendClangMajor}" clang-format + REQUIRED + ) + find_program( + RCC_BACKEND_CLANG_TIDY + NAMES "clang-tidy-${RCCBackendClangMajor}" clang-tidy + REQUIRED + ) + + foreach(Tool IN ITEMS RCC_BACKEND_CLANG_FORMAT RCC_BACKEND_CLANG_TIDY) + execute_process( + COMMAND "${${Tool}}" --version + OUTPUT_VARIABLE ToolVersionOutput + ERROR_VARIABLE ToolVersionError + RESULT_VARIABLE ToolVersionResult + ) + if(NOT ToolVersionResult EQUAL 0) + message( + FATAL_ERROR + "Unable to query ${Tool}: ${ToolVersionOutput}${ToolVersionError}" + ) + endif() + + string(REGEX MATCH "version[ \t]+([0-9]+)" ToolVersionMatch "${ToolVersionOutput}") + if(NOT CMAKE_MATCH_1 STREQUAL RCCBackendClangMajor) + message( + FATAL_ERROR + "${Tool} must have Clang major version ${RCCBackendClangMajor}: " + "${ToolVersionOutput}" + ) + endif() + endforeach() + + set(RCC_BACKEND_CLANG_FORMAT "${RCC_BACKEND_CLANG_FORMAT}" PARENT_SCOPE) + set(RCC_BACKEND_CLANG_TIDY "${RCC_BACKEND_CLANG_TIDY}" PARENT_SCOPE) +endfunction() + +function(rcc_backend_configure_target Target) + target_compile_features("${Target}" PUBLIC cxx_std_23) + set_target_properties( + "${Target}" + PROPERTIES + CXX_EXTENSIONS OFF + CXX_STANDARD 23 + CXX_STANDARD_REQUIRED ON + ) + + target_compile_options( + "${Target}" + PRIVATE + -Wall + -Wextra + -Wpedantic + -Wconversion + -Wsign-conversion + -Wshadow + -Wnon-virtual-dtor + -Wold-style-cast + -Wcast-align + -Woverloaded-virtual + -Wnull-dereference + -Wdouble-promotion + -Wformat=2 + ) + + if(RCC_BACKEND_WARNINGS_AS_ERRORS) + target_compile_options("${Target}" PRIVATE -Werror) + endif() + + if(RCC_BACKEND_ENABLE_CLANG_TIDY) + set_target_properties( + "${Target}" + PROPERTIES + CXX_CLANG_TIDY + "${RCC_BACKEND_CLANG_TIDY};--warnings-as-errors=*" + ) + endif() +endfunction() + +function(rcc_backend_register_format_files) + set_property(GLOBAL APPEND PROPERTY RCC_BACKEND_FORMAT_FILES ${ARGN}) +endfunction() + +function(rcc_backend_register_tidy_files) + set_property(GLOBAL APPEND PROPERTY RCC_BACKEND_TIDY_FILES ${ARGN}) +endfunction() diff --git a/backend/cmake/modules/RCCBackendDeveloperTools.cmake b/backend/cmake/modules/RCCBackendDeveloperTools.cmake new file mode 100644 index 0000000..d3693cd --- /dev/null +++ b/backend/cmake/modules/RCCBackendDeveloperTools.cmake @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +function(rcc_backend_add_developer_targets) + get_property(FormatFiles GLOBAL PROPERTY RCC_BACKEND_FORMAT_FILES) + get_property(TidyFiles GLOBAL PROPERTY RCC_BACKEND_TIDY_FILES) + + if(FormatFiles) + list(REMOVE_DUPLICATES FormatFiles) + + add_custom_target( + rcc-backend-format + COMMAND "${RCC_BACKEND_CLANG_FORMAT}" -i ${FormatFiles} + COMMAND_EXPAND_LISTS + COMMENT "Formatting RCC Backend C++ sources" + VERBATIM + ) + + add_custom_target( + rcc-backend-format-check + COMMAND "${RCC_BACKEND_CLANG_FORMAT}" --dry-run --Werror ${FormatFiles} + COMMAND_EXPAND_LISTS + COMMENT "Checking RCC Backend C++ formatting" + VERBATIM + ) + endif() + + if(TidyFiles) + list(REMOVE_DUPLICATES TidyFiles) + + add_custom_target( + rcc-backend-tidy + COMMAND + "${RCC_BACKEND_CLANG_TIDY}" --warnings-as-errors=* + "-p=${CMAKE_BINARY_DIR}" ${TidyFiles} + COMMAND_EXPAND_LISTS + COMMENT "Running clang-tidy on RCC Backend" + VERBATIM + ) + + add_custom_target( + rcc-backend-analyze + COMMAND + "${RCC_BACKEND_CLANG_TIDY}" "--checks=-*,clang-analyzer-*" + --warnings-as-errors=* "-p=${CMAKE_BINARY_DIR}" ${TidyFiles} + COMMAND_EXPAND_LISTS + COMMENT "Running Clang Static Analyzer checks on RCC Backend" + VERBATIM + ) + endif() +endfunction() diff --git a/backend/include/rcc/Support/Error.h b/backend/include/rcc/Support/Error.h new file mode 100644 index 0000000..3d50b46 --- /dev/null +++ b/backend/include/rcc/Support/Error.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_SUPPORT_ERROR_H +#define RCC_SUPPORT_ERROR_H + +#include <cstdint> +#include <expected> +#include <string> +#include <string_view> +#include <utility> + +namespace rcc { + +enum class ErrorCode : std::uint8_t { + InvalidArgument, + ParseError, + VerificationError, + Unsupported, + IoError, + InternalError, +}; + +[[nodiscard]] std::string_view getErrorCodeName(ErrorCode Code) noexcept; + +class Error final { +public: + Error(ErrorCode Code, std::string Message); + + [[nodiscard]] ErrorCode code() const noexcept { + return Code; + } + [[nodiscard]] std::string_view message() const noexcept { + return Message; + } + +private: + ErrorCode Code; + std::string Message; +}; + +template <typename ValueT> using Expected = std::expected<ValueT, Error>; + +[[nodiscard]] inline std::unexpected<Error> makeUnexpected(ErrorCode Code, std::string Message) { + return std::unexpected<Error>(Error(Code, std::move(Message))); +} + +} // namespace rcc + +#endif // RCC_SUPPORT_ERROR_H diff --git a/backend/lib/CMakeLists.txt b/backend/lib/CMakeLists.txt new file mode 100644 index 0000000..13f7c7b --- /dev/null +++ b/backend/lib/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +add_subdirectory(Support) diff --git a/backend/lib/Support/CMakeLists.txt b/backend/lib/Support/CMakeLists.txt new file mode 100644 index 0000000..88c959d --- /dev/null +++ b/backend/lib/Support/CMakeLists.txt @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +set(RCCBackendSupportSources Error.cpp) +set( + RCCBackendSupportHeaders + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Support/Error.h" +) + +add_library(RCCBackendSupport ${RCCBackendSupportSources}) +add_library(RCCBackend::Support ALIAS RCCBackendSupport) + +rcc_backend_configure_target(RCCBackendSupport) + +target_include_directories( + RCCBackendSupport + PUBLIC + "$<BUILD_INTERFACE:${RCC_BACKEND_SOURCE_DIR}/include>" + "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" +) + +set_target_properties( + RCCBackendSupport + PROPERTIES + EXPORT_NAME Support + OUTPUT_NAME RCCBackendSupport +) + +install( + TARGETS RCCBackendSupport + EXPORT RCCBackendTargets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" +) + +rcc_backend_register_format_files( + "${CMAKE_CURRENT_SOURCE_DIR}/Error.cpp" + ${RCCBackendSupportHeaders} +) +rcc_backend_register_tidy_files("${CMAKE_CURRENT_SOURCE_DIR}/Error.cpp") diff --git a/backend/lib/Support/Error.cpp b/backend/lib/Support/Error.cpp new file mode 100644 index 0000000..dc7d590 --- /dev/null +++ b/backend/lib/Support/Error.cpp @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/Support/Error.h" + +namespace rcc { + +std::string_view getErrorCodeName(ErrorCode Code) noexcept { + switch (Code) { + case ErrorCode::InvalidArgument: + return "invalid argument"; + case ErrorCode::ParseError: + return "parse error"; + case ErrorCode::VerificationError: + return "verification error"; + case ErrorCode::Unsupported: + return "unsupported"; + case ErrorCode::IoError: + return "I/O error"; + case ErrorCode::InternalError: + return "internal error"; + } + + return "unknown error"; +} + +Error::Error(ErrorCode Code, std::string Message) : Code(Code), Message(std::move(Message)) {} + +} // namespace rcc diff --git a/backend/unittests/CMakeLists.txt b/backend/unittests/CMakeLists.txt new file mode 100644 index 0000000..13f7c7b --- /dev/null +++ b/backend/unittests/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +add_subdirectory(Support) diff --git a/backend/unittests/Support/CMakeLists.txt b/backend/unittests/Support/CMakeLists.txt new file mode 100644 index 0000000..0c0aabc --- /dev/null +++ b/backend/unittests/Support/CMakeLists.txt @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +set(RCCBackendSupportTestSources ErrorTest.cpp) + +add_executable(RCCBackendSupportTests ${RCCBackendSupportTestSources}) +rcc_backend_configure_target(RCCBackendSupportTests) +target_link_libraries(RCCBackendSupportTests PRIVATE RCCBackend::Support) + +add_test(NAME RCCBackend.Support.Error COMMAND RCCBackendSupportTests) + +rcc_backend_register_format_files( + "${CMAKE_CURRENT_SOURCE_DIR}/ErrorTest.cpp" +) +rcc_backend_register_tidy_files( + "${CMAKE_CURRENT_SOURCE_DIR}/ErrorTest.cpp" +) diff --git a/backend/unittests/Support/ErrorTest.cpp b/backend/unittests/Support/ErrorTest.cpp new file mode 100644 index 0000000..23140e3 --- /dev/null +++ b/backend/unittests/Support/ErrorTest.cpp @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/Support/Error.h" + +#include <iostream> +#include <string> + +namespace { + +int fail(const char *Message) { + std::cerr << Message << '\n'; + return 1; +} + +} // namespace + +int main() { + rcc::Expected<int> Value = 42; + if (!Value || *Value != 42) + return fail("Expected must preserve a successful value"); + + rcc::Expected<int> Failure = rcc::makeUnexpected(rcc::ErrorCode::ParseError, "bad MIR"); + if (Failure) + return fail("Expected must preserve an error"); + if (Failure.error().code() != rcc::ErrorCode::ParseError) + return fail("Error must preserve its code"); + if (Failure.error().message() != "bad MIR") + return fail("Error must preserve its message"); + if (rcc::getErrorCodeName(Failure.error().code()) != "parse error") + return fail("Error code must have a stable name"); + + return 0; +} |
