diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index d3641987954bee31bbc7d753f8ad60e1873cc73a..14af14996ca8c3045ccd83aa19dc5154a54811d4 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -45,6 +45,7 @@ These modules are loaded using the :command:`include` command.
    /module/CheckOBJCXXSourceRuns
    /module/CheckPIESupported
    /module/CheckPrototypeDefinition
+   /module/CheckCompilerFlag
    /module/CheckSourceCompiles
    /module/CheckSourceRuns
    /module/CheckStructHasMember
diff --git a/Help/module/CheckCompilerFlag.rst b/Help/module/CheckCompilerFlag.rst
new file mode 100644
index 0000000000000000000000000000000000000000..bcf19a85353d89a30078299e1819d25da14ce5d1
--- /dev/null
+++ b/Help/module/CheckCompilerFlag.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckCompilerFlag.cmake
diff --git a/Help/release/dev/check-source-modules.rst b/Help/release/dev/check-source-modules.rst
index 9a7785a8fb2e298512d739c6e505807f0f506c90..e6cccbecd14c69c3f2a771f54a0394670f8834e7 100644
--- a/Help/release/dev/check-source-modules.rst
+++ b/Help/release/dev/check-source-modules.rst
@@ -8,3 +8,7 @@ check-source-modules
 * The :module:`CheckSourceRuns` module has been added to
   generalize :module:`CheckCSourceRuns` and
   :module:`CheckCXXSourceRuns` to more languages.
+
+* The :module:`CheckCompilerFlag` module has been added to
+  generalize :module:`CheckCCompilerFlag` and
+  :module:`CheckCXXCompilerFlag` to more languages.
diff --git a/Modules/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake
index 1452b518666ab6cec882d23223345279565e2af2..f835f29692c1a01c360a6b2a528f09f6866aa9e3 100644
--- a/Modules/CheckCCompilerFlag.cmake
+++ b/Modules/CheckCCompilerFlag.cmake
@@ -34,24 +34,8 @@ effect or even a specific one is beyond the scope of this module.
 
 include_guard(GLOBAL)
 include(CheckCSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
-
-function(check_c_compiler_flag _flag _var)
-  set(CMAKE_REQUIRED_DEFINITIONS "${_flag}")
-
-  # Normalize locale during test compilation.
-  set(_locale_vars LC_ALL LC_MESSAGES LANG)
-  foreach(v IN LISTS _locale_vars)
-    set(_locale_vars_saved_${v} "$ENV{${v}}")
-    set(ENV{${v}} C)
-  endforeach()
-  check_compiler_flag_common_patterns(_common_patterns)
-  check_c_source_compiles("int main(void) { return 0; }" ${_var}
-    # Some compilers do not fail with a bad flag
-    FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU
-    ${_common_patterns}
-    )
-  foreach(v IN LISTS _locale_vars)
-    set(ENV{${v}} ${_locale_vars_saved_${v}})
-  endforeach()
-endfunction()
+include(CheckCompilerFlag)
+
+macro (CHECK_C_COMPILER_FLAG _FLAG _RESULT)
+  check_compiler_flag(C "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake
index 544e9ac60c0f4973e697b0c66650dca2e03e813c..ce49ae3e690cb3a4951919713034070d64f02d9f 100644
--- a/Modules/CheckCXXCompilerFlag.cmake
+++ b/Modules/CheckCXXCompilerFlag.cmake
@@ -34,24 +34,8 @@ effect or even a specific one is beyond the scope of this module.
 
 include_guard(GLOBAL)
 include(CheckCXXSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
-
-function(check_cxx_compiler_flag _flag _var)
-  set(CMAKE_REQUIRED_DEFINITIONS "${_flag}")
-
-  # Normalize locale during test compilation.
-  set(_locale_vars LC_ALL LC_MESSAGES LANG)
-  foreach(v IN LISTS _locale_vars)
-    set(_locale_vars_saved_${v} "$ENV{${v}}")
-    set(ENV{${v}} C)
-  endforeach()
-  check_compiler_flag_common_patterns(_common_patterns)
-  check_cxx_source_compiles("int main() { return 0; }" ${_var}
-    # Some compilers do not fail with a bad flag
-    FAIL_REGEX "command line option .* is valid for .* but not for C\\\\+\\\\+" # GNU
-    ${_common_patterns}
-    )
-  foreach(v IN LISTS _locale_vars)
-    set(ENV{${v}} ${_locale_vars_saved_${v}})
-  endforeach()
-endfunction()
+include(CheckCompilerFlag)
+
+macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
+  check_compiler_flag(CXX "${_FLAG}" ${_RESULT})
+endmacro ()
diff --git a/Modules/CheckCompilerFlag.cmake b/Modules/CheckCompilerFlag.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..9223009fd1db81bd603644af3d8c7c3e01dea581
--- /dev/null
+++ b/Modules/CheckCompilerFlag.cmake
@@ -0,0 +1,105 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckCompilerFlag
+---------------------
+
+.. versionadded:: 3.19
+
+Check whether the compiler supports a given flag.
+
+.. command:: check_compiler_flag
+
+  .. code-block:: cmake
+
+    check_compiler_flag(<lang> <flag> <var>)
+
+Check that the ``<flag>`` is accepted by the compiler without a diagnostic.
+Stores the result in an internal cache entry named ``<var>``.
+
+This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable
+and calls the ``check_source_compiles(<LANG>`` function from the
+:module:`CheckSourceCompiles` module.  See documentation of that
+module for a listing of variables that can otherwise modify the build.
+
+A positive result from this check indicates only that the compiler did not
+issue a diagnostic message when given the flag.  Whether the flag has any
+effect or even a specific one is beyond the scope of this module.
+
+.. note::
+  Since the :command:`try_compile` command forwards flags from variables
+  like :variable:`CMAKE_<LANG>_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags
+  in such variables may cause a false negative for this check.
+#]=======================================================================]
+
+include_guard(GLOBAL)
+include(CheckSourceCompiles)
+include(CMakeCheckCompilerFlagCommonPatterns)
+
+cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
+cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
+
+function(CHECK_COMPILER_FLAG _lang _flag _var)
+
+  if(_lang STREQUAL C)
+    set(_lang_src "int main(void) { return 0; }")
+    set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for C")
+  elseif(_lang STREQUAL CXX)
+    set(_lang_src "int main() { return 0; }")
+    set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for C\\+\\+")
+  elseif(_lang STREQUAL Fortran)
+    set(_lang_src "       program test\n       stop\n       end program")
+    set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Fortran")
+  elseif(_lang STREQUAL OBJC)
+    set(_lang_src [=[
+#ifndef __OBJC__
+#  error "Not an Objective-C compiler"
+#endif
+int main(void) { return 0; }]=])
+    set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Objective-C" # GNU
+                         FAIL_REGEX "argument unused during compilation: .*") # Clang
+  elseif(_lang STREQUAL OBJCXX)
+    set(_lang_src [=[
+#ifndef __OBJC__
+#  error "Not an Objective-C++ compiler"
+#endif
+int main(void) { return 0; }]=])
+    set(_lang_fail_regex FAIL_REGEX "command line option .* is valid for .* but not for Objective-C\\+\\+" # GNU
+                         FAIL_REGEX "argument unused during compilation: .*") # Clang
+  else()
+    message (SEND_ERROR "check_compiler_flag: ${_lang}: unknown language.")
+    return()
+  endif()
+
+  get_property (_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+  if (NOT _lang IN_LIST _supported_languages)
+    message (SEND_ERROR "check_compiler_flag: ${_lang}: needs to be enabled before use.")
+    return()
+  endif()
+
+  set(CMAKE_REQUIRED_DEFINITIONS ${_flag})
+
+  # Normalize locale during test compilation.
+  set(_locale_vars LC_ALL LC_MESSAGES LANG)
+  foreach(v IN LISTS _locale_vars)
+    set(_locale_vars_saved_${v} "$ENV{${v}}")
+    set(ENV{${v}} C)
+  endforeach()
+
+  check_compiler_flag_common_patterns(_common_patterns)
+  check_source_compiles(${_lang}
+    "${_lang_src}"
+    ${_var}
+    ${_lang_fail_regex}
+    ${_common_patterns}
+    )
+
+  foreach(v IN LISTS _locale_vars)
+    set(ENV{${v}} ${_locale_vars_saved_${v}})
+  endforeach()
+  set(${_var} "${${_var}}" PARENT_SCOPE)
+endfunction ()
+
+cmake_policy(POP)
diff --git a/Modules/CheckFortranCompilerFlag.cmake b/Modules/CheckFortranCompilerFlag.cmake
index b8fac97cc537e621ad48bbff2040c1a1a8e7ebad..0f5cf9a248dec2024005d7bfb32ad67db1157244 100644
--- a/Modules/CheckFortranCompilerFlag.cmake
+++ b/Modules/CheckFortranCompilerFlag.cmake
@@ -36,30 +36,8 @@ effect or even a specific one is beyond the scope of this module.
 
 include_guard(GLOBAL)
 include(CheckFortranSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
+include(CheckCompilerFlag)
 
-macro (CHECK_Fortran_COMPILER_FLAG _FLAG _RESULT)
-  set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
-  set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
-
-  # Normalize locale during test compilation.
-  set(_CheckFortranCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
-  foreach(v ${_CheckFortranCompilerFlag_LOCALE_VARS})
-    set(_CheckFortranCompilerFlag_SAVED_${v} "$ENV{${v}}")
-    set(ENV{${v}} C)
-  endforeach()
-  CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckFortranCompilerFlag_COMMON_PATTERNS)
-  CHECK_Fortran_SOURCE_COMPILES("       program test\n       stop\n       end program" ${_RESULT}
-    # Some compilers do not fail with a bad flag
-    FAIL_REGEX "command line option .* is valid for .* but not for Fortran" # GNU
-    ${_CheckFortranCompilerFlag_COMMON_PATTERNS}
-    )
-  foreach(v ${_CheckFortranCompilerFlag_LOCALE_VARS})
-    set(ENV{${v}} ${_CheckFortranCompilerFlag_SAVED_${v}})
-    unset(_CheckFortranCompilerFlag_SAVED_${v})
-  endforeach()
-  unset(_CheckFortranCompilerFlag_LOCALE_VARS)
-  unset(_CheckFortranCompilerFlag_COMMON_PATTERNS)
-
-  set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+macro (CHECK_FORTRAN_COMPILER_FLAG _FLAG _RESULT)
+  check_compiler_flag(Fortran "${_FLAG}" ${_RESULT})
 endmacro ()
diff --git a/Modules/CheckOBJCCompilerFlag.cmake b/Modules/CheckOBJCCompilerFlag.cmake
index a98f4293c926a2ed47488d2d8f4584647f3bcae7..df9d724bbff8da3206ba7d3fc13673ca718699b7 100644
--- a/Modules/CheckOBJCCompilerFlag.cmake
+++ b/Modules/CheckOBJCCompilerFlag.cmake
@@ -36,31 +36,8 @@ effect or even a specific one is beyond the scope of this module.
 
 include_guard(GLOBAL)
 include(CheckOBJCSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
+include(CheckCompilerFlag)
 
 macro (CHECK_OBJC_COMPILER_FLAG _FLAG _RESULT)
-  set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
-  set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
-
-   # Normalize locale during test compilation.
-  set(_CheckOBJCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
-  foreach(v ${_CheckOBJCCompilerFlag_LOCALE_VARS})
-    set(_CheckOBJCCompilerFlag_SAVED_${v} "$ENV{${v}}")
-    set(ENV{${v}} OBJC)
-  endforeach()
-  CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckOBJCCompilerFlag_COMMON_PATTERNS)
-  CHECK_OBJC_SOURCE_COMPILES("#ifndef __OBJC__\n#  error \"Not an Objective-C compiler\"\n#endif\nint main(void) { return 0; }" ${_RESULT}
-    # Some compilers do not fail with a bad flag
-    FAIL_REGEX "command line option .* is valid for .* but not for Objective-C" # GNU
-    FAIL_REGEX "argument unused during compilation: .*" # Clang
-    ${_CheckOBJCCompilerFlag_COMMON_PATTERNS}
-    )
-  foreach(v ${_CheckOBJCCompilerFlag_LOCALE_VARS})
-    set(ENV{${v}} ${_CheckOBJCCompilerFlag_SAVED_${v}})
-    unset(_CheckOBJCCompilerFlag_SAVED_${v})
-  endforeach()
-  unset(_CheckOBJCCompilerFlag_LOCALE_VARS)
-  unset(_CheckOBJCCompilerFlag_COMMON_PATTERNS)
-
-  set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+  check_compiler_flag(OBJC "${_FLAG}" ${_RESULT})
 endmacro ()
diff --git a/Modules/CheckOBJCXXCompilerFlag.cmake b/Modules/CheckOBJCXXCompilerFlag.cmake
index 7944ab07a0efd06e74519d3ee1e0c7f0cc6de4eb..6e01bcc95182b244a72a8954c1ce066a885aebb1 100644
--- a/Modules/CheckOBJCXXCompilerFlag.cmake
+++ b/Modules/CheckOBJCXXCompilerFlag.cmake
@@ -36,31 +36,8 @@ effect or even a specific one is beyond the scope of this module.
 
 include_guard(GLOBAL)
 include(CheckOBJCXXSourceCompiles)
-include(CMakeCheckCompilerFlagCommonPatterns)
+include(CheckCompilerFlag)
 
 macro (CHECK_OBJCXX_COMPILER_FLAG _FLAG _RESULT)
-  set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
-  set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
-
-  # Normalize locale during test compilation.
-  set(_CheckOBJCXXCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
-  foreach(v ${_CheckOBJCXXCompilerFlag_LOCALE_VARS})
-    set(_CheckOBJCXXCompilerFlag_SAVED_${v} "$ENV{${v}}")
-    set(ENV{${v}} OBJCXX)
-  endforeach()
-  CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckOBJCXXCompilerFlag_COMMON_PATTERNS)
-  CHECK_OBJCXX_SOURCE_COMPILES("#ifndef __OBJC__\n#  error \"Not an Objective-C++ compiler\"\n#endif\nint main(void) { return 0; }" ${_RESULT}
-    # Some compilers do not fail with a bad flag
-    FAIL_REGEX "command line option .* is valid for .* but not for Objective-C\\\\+\\\\+" # GNU
-    FAIL_REGEX "argument unused during compilation: .*" # Clang
-    ${_CheckOBJCXXCompilerFlag_COMMON_PATTERNS}
-    )
-  foreach(v ${_CheckOBJCXXCompilerFlag_LOCALE_VARS})
-    set(ENV{${v}} ${_CheckOBJCXXCompilerFlag_SAVED_${v}})
-    unset(_CheckOBJCXXCompilerFlag_SAVED_${v})
-  endforeach()
-  unset(_CheckOBJCXXCompilerFlag_LOCALE_VARS)
-  unset(_CheckOBJCXXCompilerFlag_COMMON_PATTERNS)
-
-  set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+  check_compiler_flag(OBJCXX "${_FLAG}" ${_RESULT})
 endmacro ()