diff --git a/Makefile.include b/Makefile.include
index 35edb0c0e96689ef53b598852ef5364d6bc5ce79..5fe885dc90d832db39ae2e53fc5305fd014ad54e 100644
--- a/Makefile.include
+++ b/Makefile.include
@@ -241,6 +241,9 @@ include $(RIOTBOARD)/$(BOARD)/Makefile.include
 INCLUDES += -I$(RIOTCPU)/$(CPU)/include
 include $(RIOTCPU)/$(CPU)/Makefile.include
 
+# Assume GCC/GNU as supported toolchain if CPU's Makefile.include doesn't
+# provide this macro
+TOOLCHAINS_SUPPORTED ?= gnu
 # Import all toolchain settings
 include $(RIOTMAKE)/toolchain/$(TOOLCHAIN).inc.mk
 
@@ -598,6 +601,20 @@ ifneq (, $(filter all, $(if $(MAKECMDGOALS), $(MAKECMDGOALS), all)))
     endif
   endif
 
+  #  test if toolchain is supported.
+  ifeq (,$(filter $(TOOLCHAIN),$(TOOLCHAINS_SUPPORTED)))
+    $(shell $(COLOR_ECHO) "$(COLOR_RED)The selected TOOLCHAIN=$(TOOLCHAIN) is not supported.$(COLOR_RESET)\nSupported toolchains: $(TOOLCHAINS_SUPPORTED)" 1>&2)
+    EXPECT_ERRORS := 1
+  endif
+
+  # If there is a blacklist, then test if the board is blacklisted.
+  ifneq (,$(TOOLCHAINS_BLACKLIST))
+    ifneq (,$(filter $(TOOLCHAIN),$(TOOLCHAINS_BLACKLIST)))
+      $(shell $(COLOR_ECHO) "$(COLOR_RED)The selected TOOLCHAIN=$(TOOLCHAIN) is blacklisted:$(COLOR_RESET) $(TOOLCHAINS_BLACKLIST)" 1>&2)
+      EXPECT_ERRORS := 1
+    endif
+  endif
+
   ifneq (, $(EXPECT_CONFLICT))
     $(shell $(COLOR_ECHO) "\n$(COLOR_YELLOW)EXPECT undesired behaviour!$(COLOR_RESET)" 1>&2)
   endif
diff --git a/cpu/cortexm_common/Makefile.include b/cpu/cortexm_common/Makefile.include
index b1be7aff71fbf04ed87ba44eb160a664b1c25e9a..60e5938bc439bdc1679bc34e6cf016ff3abbe387 100644
--- a/cpu/cortexm_common/Makefile.include
+++ b/cpu/cortexm_common/Makefile.include
@@ -15,6 +15,7 @@ ifneq (,$(ROM_START_ADDR)$(RAM_START_ADDR)$(ROM_LEN)$(RAM_LEN))
   LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_ram_length=$(RAM_LEN)
 endif
 
+TOOLCHAINS_SUPPORTED = gnu llvm
 
 # Only define the linker symbol if the variable is set
 # The variable can be set using target specific variable thanks to lazy evaluation
diff --git a/cpu/native/Makefile.include b/cpu/native/Makefile.include
index b02f64a1daf92a461c64c48dd1811aa510a9c3f6..76ddd9ead04c637dc7976d114589982cd0aa631f 100644
--- a/cpu/native/Makefile.include
+++ b/cpu/native/Makefile.include
@@ -10,3 +10,5 @@ USEMODULE += periph_uart
 
 # include common peripheral initialization
 USEMODULE += periph_common
+
+TOOLCHAINS_SUPPORTED = gnu llvm
diff --git a/makefiles/buildtests.inc.mk b/makefiles/buildtests.inc.mk
index e67f9f4982098093d3c02d2db2abff912b616dc1..3d560590af30c53c0585dc69751d2aebe52e5f43 100644
--- a/makefiles/buildtests.inc.mk
+++ b/makefiles/buildtests.inc.mk
@@ -9,17 +9,19 @@ buildtest:
 	@ \
 	RESULT=true ; \
 	for board in $(BOARDS); do \
-		$(COLOR_ECHO) -n "Building for $$board ... " ; \
-		BOARD=$${board} RIOT_CI_BUILD=1 RIOT_VERSION_OVERRIDE=buildtest \
-			$(MAKE) clean all -j $(NPROC) $(BUILDTEST_MAKE_REDIRECT); \
-		RES=$$? ; \
-		if [ $$RES -eq 0 ]; then \
-			$(COLOR_ECHO) "$(COLOR_GREEN)success.$(COLOR_RESET)" ; \
-		else \
-			$(COLOR_ECHO) "$(COLOR_RED)failed!$(COLOR_RESET)" ; \
-			RESULT=false ; \
-		fi ; \
-		$(MAKE) clean-intermediates >/dev/null 2>&1 || true; \
+		if BOARD=$${board} $(MAKE) check-toolchain-supported > /dev/null 2>&1; then \
+			$(COLOR_ECHO) -n "Building for $$board ... " ; \
+			BOARD=$${board} RIOT_CI_BUILD=1 RIOT_VERSION_OVERRIDE=buildtest \
+				$(MAKE) clean all -j $(NPROC) $(BUILDTEST_MAKE_REDIRECT); \
+			RES=$$? ; \
+			if [ $$RES -eq 0 ]; then \
+				$(COLOR_ECHO) "$(COLOR_GREEN)success.$(COLOR_RESET)" ; \
+			else \
+				$(COLOR_ECHO) "$(COLOR_RED)failed!$(COLOR_RESET)" ; \
+				RESULT=false ; \
+			fi ; \
+			$(MAKE) clean-intermediates >/dev/null 2>&1 || true; \
+		fi; \
 	done ; \
 	$${RESULT}
 endif # BUILD_IN_DOCKER
diff --git a/makefiles/info.inc.mk b/makefiles/info.inc.mk
index 0eb1bf46dffc5f0eb4ceca831c287a5b1743b321..7003ce478456cf7693978934c6b63465a942a1db 100644
--- a/makefiles/info.inc.mk
+++ b/makefiles/info.inc.mk
@@ -1,7 +1,8 @@
 .PHONY: info-objsize info-buildsizes info-build info-boards-supported \
         info-features-missing info-modules info-cpu \
         info-features-provided info-features-required \
-        info-debug-variable-%
+        info-debug-variable-% info-toolchains-supported \
+        check-toolchain-supported
 
 info-objsize:
 	@case "$(SORTROW)" in \
@@ -130,3 +131,9 @@ info-features-missing:
 
 info-debug-variable-%:
 	@echo $($*)
+
+info-toolchains-supported:
+	@echo $(filter-out $(TOOLCHAINS_BLACKLIST),$(TOOLCHAINS_SUPPORTED))
+
+check-toolchain-supported:
+	@exit $(if $(filter $(TOOLCHAIN),$(filter-out $(TOOLCHAINS_BLACKLIST),$(TOOLCHAINS_SUPPORTED))),0,1)
diff --git a/makefiles/vars.inc.mk b/makefiles/vars.inc.mk
index 7194443c846e7a4faf72f032eb21ac0a2d02da5b..abe85369911e63c98934fa02cb5a0e3e8de04e73 100644
--- a/makefiles/vars.inc.mk
+++ b/makefiles/vars.inc.mk
@@ -36,6 +36,8 @@ export PYTHONPATH            # Python default search path for module filesi, wit
 export FEATURES_REQUIRED     # List of required features by the application
 export FEATURES_PROVIDED     # List of provided features by the board
 export FEATURES_OPTIONAL     # List of nice to have features
+# TOOLCHAINS_SUPPORTED       # List of supported toolchains by an MCU (gnu/llvm/...).
+# TOOLCHAINS_BLACKLISTED     # List of unspported toolchains for a module or an application.
 
 export TARGET_ARCH           # The target platform name, in GCC triple notation, e.g. "arm-none-eabi", "i686-elf", "avr"
 export PREFIX                # The prefix of the toolchain commands, usually "$(TARGET_ARCH)-", e.g. "arm-none-eabi-" or "msp430-".