Index: clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp +++ clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp @@ -60,8 +60,24 @@ AST_MATCHER(QualType, isVAList) { ASTContext &Context = Finder->getASTContext(); QualType Desugar = Node.getDesugaredType(Context); - return Context.getBuiltinVaListType().getDesugaredType(Context) == Desugar || - Context.getBuiltinMSVaListType().getDesugaredType(Context) == Desugar; + + // __builtin_ms_va_list is internally implemented as 'char *'. This means that + // the node desugared as 'char *' potentially can be a __builtin_ms_va_list. + // So we need to remove all typedefs one by one to check this. + if (Desugar == Context.getBuiltinMSVaListType().getDesugaredType(Context)) { + const auto MSVaListType = Context.getBuiltinMSVaListType(); + QualType Ty; + do { + Ty = Desugar; + Desugar = Ty.getSingleStepDesugaredType(Context); + if (Desugar == MSVaListType) + return true; + } while (Desugar != Ty); + // No need to check the other cases. We have a regular pointer here. + return false; + } + + return Context.getBuiltinVaListType().getDesugaredType(Context) == Desugar; } AST_MATCHER_P(AdjustedType, hasOriginalType, Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg-ms.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg-ms.cpp @@ -0,0 +1,26 @@ +// Purpose: +// Ensure that the 'cppcoreguidelines-pro-type-vararg' check works with the +// built-in va_list on Windows systems. + +// REQUIRES: system-windows + +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-vararg %t + +void test_ms_va_list(int a, ...) { + __builtin_ms_va_list ap; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead + __builtin_ms_va_start(ap, a); + int b = __builtin_va_arg(ap, int); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use va_arg to define c-style vararg functions; use variadic templates instead + __builtin_ms_va_end(ap); +} + +void test_typedefs(int a, ...) { + typedef __builtin_ms_va_list my_va_list1; + my_va_list1 ap1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead + + using my_va_list2 = __builtin_ms_va_list; + my_va_list2 ap2; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead +} Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp +++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp @@ -58,3 +58,7 @@ (void)__builtin_isinf_sign(0.f); (void)__builtin_prefetch(nullptr); } + +// __builtin_ms_va_list desugared as 'char *'. This test checks whether we are +// handling this case correctly and not generating false positives. +void no_false_positive_desugar_ms_va_list(char *in) { char *tmp = in; }