summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp33
-rw-r--r--clang/lib/Frontend/VerifyDiagnosticConsumer.cpp130
2 files changed, 122 insertions, 41 deletions
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index be907d9ba85..9fabcdf05a8 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1071,6 +1071,26 @@ static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) {
llvm::sys::Process::StandardErrHasColors());
}
+static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes,
+ DiagnosticsEngine *Diags) {
+ bool Success = true;
+ for (const auto &Prefix : VerifyPrefixes) {
+ // Every prefix must start with a letter and contain only alphanumeric
+ // characters, hyphens, and underscores.
+ auto BadChar = std::find_if(Prefix.begin(), Prefix.end(),
+ [](char C){return !isAlphanumeric(C)
+ && C != '-' && C != '_';});
+ if (BadChar != Prefix.end() || !isLetter(Prefix[0])) {
+ Success = false;
+ if (Diags) {
+ Diags->Report(diag::err_drv_invalid_value) << "-verify=" << Prefix;
+ Diags->Report(diag::note_drv_verify_prefix_spelling);
+ }
+ }
+ }
+ return Success;
+}
+
bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
DiagnosticsEngine *Diags,
bool DefaultDiagColor, bool DefaultShowOpt) {
@@ -1158,7 +1178,18 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
Opts.ShowPresumedLoc = !Args.hasArg(OPT_fno_diagnostics_use_presumed_location);
- Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+ Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ);
+ Opts.VerifyPrefixes = Args.getAllArgValues(OPT_verify_EQ);
+ if (Args.hasArg(OPT_verify))
+ Opts.VerifyPrefixes.push_back("expected");
+ // Keep VerifyPrefixes in its original order for the sake of diagnostics, and
+ // then sort it to prepare for fast lookup using std::binary_search.
+ if (!checkVerifyPrefixes(Opts.VerifyPrefixes, Diags)) {
+ Opts.VerifyDiagnostics = false;
+ Success = false;
+ }
+ else
+ std::sort(Opts.VerifyPrefixes.begin(), Opts.VerifyPrefixes.end());
DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None;
Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=",
Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ),
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index a49c424e915..0df5393a309 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -229,22 +229,52 @@ public:
return true;
}
- // Return true if string literal is found.
- // When true, P marks begin-position of S in content.
- bool Search(StringRef S, bool EnsureStartOfWord = false) {
+ // Return true if string literal S is matched in content.
+ // When true, P marks begin-position of the match, and calling Advance sets C
+ // to end-position of the match.
+ // If S is the empty string, then search for any letter instead (makes sense
+ // with FinishDirectiveToken=true).
+ // If EnsureStartOfWord, then skip matches that don't start a new word.
+ // If FinishDirectiveToken, then assume the match is the start of a comment
+ // directive for -verify, and extend the match to include the entire first
+ // token of that directive.
+ bool Search(StringRef S, bool EnsureStartOfWord = false,
+ bool FinishDirectiveToken = false) {
do {
- P = std::search(C, End, S.begin(), S.end());
- PEnd = P + S.size();
+ if (!S.empty()) {
+ P = std::search(C, End, S.begin(), S.end());
+ PEnd = P + S.size();
+ }
+ else {
+ P = C;
+ while (P != End && !isLetter(*P))
+ ++P;
+ PEnd = P + 1;
+ }
if (P == End)
break;
- if (!EnsureStartOfWord
- // Check if string literal starts a new word.
- || P == Begin || isWhitespace(P[-1])
- // Or it could be preceded by the start of a comment.
- || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
- && P[-2] == '/'))
- return true;
- // Otherwise, skip and search again.
+ // If not start of word but required, skip and search again.
+ if (EnsureStartOfWord
+ // Check if string literal starts a new word.
+ && !(P == Begin || isWhitespace(P[-1])
+ // Or it could be preceded by the start of a comment.
+ || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
+ && P[-2] == '/')))
+ continue;
+ if (FinishDirectiveToken) {
+ while (PEnd != End && (isAlphanumeric(*PEnd)
+ || *PEnd == '-' || *PEnd == '_'))
+ ++PEnd;
+ // Put back trailing digits and hyphens to be parsed later as a count
+ // or count range. Because -verify prefixes must start with letters,
+ // we know the actual directive we found starts with a letter, so
+ // we won't put back the entire directive word and thus record an empty
+ // string.
+ assert(isLetter(*P) && "-verify prefix must start with a letter");
+ while (isDigit(PEnd[-1]) || PEnd[-1] == '-')
+ --PEnd;
+ }
+ return true;
} while (Advance());
return false;
}
@@ -314,37 +344,68 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// A single comment may contain multiple directives.
bool FoundDirective = false;
for (ParseHelper PH(S); !PH.Done();) {
- // Search for token: expected
- if (!PH.Search("expected", true))
+ // Search for the initial directive token.
+ // If one prefix, save time by searching only for its directives.
+ // Otherwise, search for any potential directive token and check it later.
+ const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes;
+ if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true)
+ : PH.Search("", true, true)))
break;
PH.Advance();
- // Next token: -
- if (!PH.Next("-"))
- continue;
- PH.Advance();
+ // Default directive kind.
+ bool RegexKind = false;
+ const char* KindStr = "string";
+
+ // Parse the initial directive token in reverse so we can easily determine
+ // its exact actual prefix. If we were to parse it from the front instead,
+ // it would be harder to determine where the prefix ends because there
+ // might be multiple matching -verify prefixes because some might prefix
+ // others.
+ StringRef DToken(PH.P, PH.C - PH.P);
- // Next token: { error | warning | note }
+ // Regex in initial directive token: -re
+ if (DToken.endswith("-re")) {
+ RegexKind = true;
+ KindStr = "regex";
+ DToken = DToken.substr(0, DToken.size()-3);
+ }
+
+ // Type in initial directive token: -{error|warning|note|no-diagnostics}
DirectiveList *DL = nullptr;
- if (PH.Next("error"))
+ bool NoDiag = false;
+ StringRef DType;
+ if (DToken.endswith(DType="-error"))
DL = ED ? &ED->Errors : nullptr;
- else if (PH.Next("warning"))
+ else if (DToken.endswith(DType="-warning"))
DL = ED ? &ED->Warnings : nullptr;
- else if (PH.Next("remark"))
+ else if (DToken.endswith(DType="-remark"))
DL = ED ? &ED->Remarks : nullptr;
- else if (PH.Next("note"))
+ else if (DToken.endswith(DType="-note"))
DL = ED ? &ED->Notes : nullptr;
- else if (PH.Next("no-diagnostics")) {
+ else if (DToken.endswith(DType="-no-diagnostics")) {
+ NoDiag = true;
+ if (RegexKind)
+ continue;
+ }
+ else
+ continue;
+ DToken = DToken.substr(0, DToken.size()-DType.size());
+
+ // What's left in DToken is the actual prefix. That might not be a -verify
+ // prefix even if there is only one -verify prefix (for example, the full
+ // DToken is foo-bar-warning, but foo is the only -verify prefix).
+ if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken))
+ continue;
+
+ if (NoDiag) {
if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
<< /*IsExpectedNoDiagnostics=*/true;
else
Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
continue;
- } else
- continue;
- PH.Advance();
-
+ }
if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
<< /*IsExpectedNoDiagnostics=*/false;
@@ -357,17 +418,6 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
if (!DL)
return true;
- // Default directive kind.
- bool RegexKind = false;
- const char* KindStr = "string";
-
- // Next optional token: -
- if (PH.Next("-re")) {
- PH.Advance();
- RegexKind = true;
- KindStr = "regex";
- }
-
// Next optional token: @
SourceLocation ExpectedLoc;
bool MatchAnyLine = false;
OpenPOWER on IntegriCloud