diff --git a/llvm/include/llvm/FileCheck/FileCheck.h b/llvm/include/llvm/FileCheck/FileCheck.h --- a/llvm/include/llvm/FileCheck/FileCheck.h +++ b/llvm/include/llvm/FileCheck/FileCheck.h @@ -30,6 +30,7 @@ std::vector ImplicitCheckNot; std::vector GlobalDefines; bool AllowEmptyInput = false; + bool AllowUnusedPrefixes = false; bool MatchFullLines = false; bool IgnoreCase = false; bool IsDefaultCheckPrefix = false; diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp --- a/llvm/lib/FileCheck/FileCheck.cpp +++ b/llvm/lib/FileCheck/FileCheck.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/FormatVariadic.h" #include #include +#include #include #include @@ -1825,8 +1826,10 @@ // found. unsigned LineNumber = 1; - bool FoundUsedCheckPrefix = false; - while (1) { + std::set PrefixesNotFound(Req.CheckPrefixes.begin(), + Req.CheckPrefixes.end()); + const size_t DistinctPrefixes = PrefixesNotFound.size(); + while (true) { Check::FileCheckType CheckTy; // See if a prefix occurs in the memory buffer. @@ -1837,7 +1840,7 @@ if (UsedPrefix.empty()) break; if (CheckTy != Check::CheckComment) - FoundUsedCheckPrefix = true; + PrefixesNotFound.erase(UsedPrefix); assert(UsedPrefix.data() == Buffer.data() && "Failed to move Buffer's start forward, or pointed prefix outside " @@ -1930,14 +1933,19 @@ // When there are no used prefixes we report an error except in the case that // no prefix is specified explicitly but -implicit-check-not is specified. - if (!FoundUsedCheckPrefix && + const bool NoPrefixesFound = PrefixesNotFound.size() == DistinctPrefixes; + const bool SomePrefixesUnexpectedlyNotUsed = + !Req.AllowUnusedPrefixes && !PrefixesNotFound.empty(); + if ((NoPrefixesFound || SomePrefixesUnexpectedlyNotUsed) && (ImplicitNegativeChecks.empty() || !Req.IsDefaultCheckPrefix)) { errs() << "error: no check strings found with prefix" - << (Req.CheckPrefixes.size() > 1 ? "es " : " "); - for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) { - if (I != 0) + << (PrefixesNotFound.size() > 1 ? "es " : " "); + bool First = true; + for (StringRef MissingPrefix : PrefixesNotFound) { + if (!First) errs() << ", "; - errs() << "\'" << Req.CheckPrefixes[I] << ":'"; + errs() << "\'" << MissingPrefix << ":'"; + First = false; } errs() << '\n'; return true; diff --git a/llvm/test/FileCheck/Inputs/one-check.txt b/llvm/test/FileCheck/Inputs/one-check.txt new file mode 100644 --- /dev/null +++ b/llvm/test/FileCheck/Inputs/one-check.txt @@ -0,0 +1,2 @@ +hello +; P1: hello \ No newline at end of file diff --git a/llvm/test/FileCheck/allow-unused-prefixes.txt b/llvm/test/FileCheck/allow-unused-prefixes.txt new file mode 100644 --- /dev/null +++ b/llvm/test/FileCheck/allow-unused-prefixes.txt @@ -0,0 +1,10 @@ +; RUN: not FileCheck --allow-unused-prefixes=false --check-prefixes=P1,P2 --input-file %S/Inputs/one-check.txt %S/Inputs/one-check.txt 2>&1 | FileCheck --check-prefix=MISSING-ONE %s +; RUN: not FileCheck --allow-unused-prefixes=false --check-prefixes=P1,P2,P3 --input-file %S/Inputs/one-check.txt %S/Inputs/one-check.txt 2>&1 | FileCheck --check-prefix=MISSING-MORE %s +; RUN: FileCheck --allow-unused-prefixes=true --check-prefixes=P1,P2 --input-file %S/Inputs/one-check.txt %S/Inputs/one-check.txt + +; Note: the default will be changed to 'false', at which time this run line +; should be changed accordingly. +; RUN: FileCheck --check-prefixes=P1,P2 --input-file %S/Inputs/one-check.txt %S/Inputs/one-check.txt + +; MISSING-ONE: error: no check strings found with prefix 'P2:' +; MISSING-MORE: error: no check strings found with prefixes 'P2:', 'P3:' \ No newline at end of file diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp --- a/llvm/utils/FileCheck/FileCheck.cpp +++ b/llvm/utils/FileCheck/FileCheck.cpp @@ -77,6 +77,10 @@ cl::desc("Allow the input file to be empty. This is useful when making\n" "checks that some error message does not occur, for example.")); +static cl::opt AllowUnusedPrefixes( + "allow-unused-prefixes", cl::init(true), + cl::desc("Allow prefixes to be specified but not appear in the test.")); + static cl::opt MatchFullLines( "match-full-lines", cl::init(false), cl::desc("Require all positive matches to cover an entire input line.\n" @@ -771,6 +775,7 @@ return 2; Req.AllowEmptyInput = AllowEmptyInput; + Req.AllowUnusedPrefixes = AllowUnusedPrefixes; Req.EnableVarScope = EnableVarScope; Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap; Req.Verbose = Verbose;