if(SANITIZER)
  if(NOT (SANITIZER STREQUAL "Thread"))
    add_required_compiler_flag("-fno-omit-frame-pointer")
  endif()

  include(AddCompilerFlag)

  macro(append_address_sanitizer_flags)
    add_required_compiler_flag("-fsanitize=address")
    add_required_compiler_flag("-fsanitize-address-use-after-scope")
    add_required_compiler_flag("-fno-optimize-sibling-calls")
  endmacro()

  macro(append_undefined_sanitizer_flags)
    add_required_compiler_flag("-fsanitize=undefined")
    add_required_compiler_flag("-fno-sanitize-recover=all")

    if(CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?Clang")
      add_required_compiler_flag("-fsanitize=float-divide-by-zero")
      add_required_compiler_flag("-fsanitize=unsigned-integer-overflow")
      add_required_compiler_flag("-fsanitize=implicit-conversion")
      add_required_compiler_flag("-fsanitize=local-bounds")
      add_required_compiler_flag("-fsanitize=nullability")
      add_required_compiler_flag("-fsanitize-recover=unsigned-integer-overflow")
    endif()
  endmacro()

  if(SANITIZER STREQUAL "Address")
    message(STATUS "Building with AddressSanitizer")

    if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
      message(WARNING "AppleClang does not support LeakSanitizer")
    endif()

    append_address_sanitizer_flags()
  elseif(SANITIZER STREQUAL "Thread")
    message(STATUS "Building with ThreadSanitizer")
    add_required_compiler_flag("-fsanitize=thread")
  elseif(SANITIZER STREQUAL "Memory")
    if(CMAKE_COMPILER_IS_GNUCXX)
      message(FATAL_ERROR "GCC does not support MemorySanitizer")
    endif()

    if(APPLE)
      message(FATAL_ERROR "macOS does not support MemorySanitizer")
    endif()

    message(STATUS "Building with MemorySanitizer")

    add_required_compiler_flag("-fsanitize=memory")
    add_required_compiler_flag("-fsanitize-memory-track-origins")
    add_required_compiler_flag("-fno-optimize-sibling-calls")
  elseif(SANITIZER STREQUAL "Undefined")
    message(STATUS "Building with UndefinedSanitizer")
    append_undefined_sanitizer_flags()
  elseif(SANITIZER STREQUAL "Address;Undefined")
    message(STATUS "Building with AddressSanitizer and UndefinedSanitizer")
    append_address_sanitizer_flags()
    append_undefined_sanitizer_flags()
  else()
    message(FATAL_ERROR "The Sanitizer is not supported: ${SANITIZER}")
  endif()
endif()
