summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/FileCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/FileCheck.cpp')
-rw-r--r--llvm/lib/Support/FileCheck.cpp309
1 files changed, 118 insertions, 191 deletions
diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
index eab16ad6865..44e394f5b9d 100644
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -24,38 +24,11 @@
using namespace llvm;
-bool FileCheckNumericVariable::isValueKnownAtMatchTime() const {
- if (Value)
- return true;
-
- return ExpressionAST != nullptr;
-}
-
-void FileCheckNumericVariable::setValue(uint64_t NewValue) {
- if (ExpressionAST != nullptr) {
- // Caller is expected to call setValue only if substitution was successful.
- assert(NewValue == cantFail(ExpressionAST->eval(),
- "Failed to evaluate associated expression when "
- "sanity checking value") &&
- "Value being set to different from variable evaluation");
- }
- Value = NewValue;
- // Clear pointer to AST to ensure it is not used after the numeric
- // substitution defining this variable is processed since it's the
- // substitution that owns the pointer.
- ExpressionAST = nullptr;
-}
-
Expected<uint64_t> FileCheckNumericVariableUse::eval() const {
Optional<uint64_t> Value = NumericVariable->getValue();
if (Value)
return *Value;
-
- FileCheckExpressionAST *ExpressionAST = NumericVariable->getExpressionAST();
- if (!ExpressionAST)
- return make_error<FileCheckUndefVarError>(Name);
-
- return ExpressionAST->eval();
+ return make_error<FileCheckUndefVarError>(Name);
}
Expected<uint64_t> FileCheckASTBinop::eval() const {
@@ -141,8 +114,7 @@ char FileCheckNotFoundError::ID = 0;
Expected<FileCheckNumericVariable *>
FileCheckPattern::parseNumericVariableDefinition(
StringRef &Expr, FileCheckPatternContext *Context,
- Optional<size_t> LineNumber, FileCheckExpressionAST *ExpressionAST,
- const SourceMgr &SM) {
+ Optional<size_t> LineNumber, const SourceMgr &SM) {
Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
if (!ParseVarResult)
return ParseVarResult.takeError();
@@ -169,17 +141,14 @@ FileCheckPattern::parseNumericVariableDefinition(
if (VarTableIter != Context->GlobalNumericVariableTable.end())
DefinedNumericVariable = VarTableIter->second;
else
- DefinedNumericVariable =
- Context->makeNumericVariable(Name, LineNumber, ExpressionAST);
+ DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber);
return DefinedNumericVariable;
}
Expected<std::unique_ptr<FileCheckNumericVariableUse>>
FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
- Optional<size_t> LineNumber,
- FileCheckPatternContext *Context,
- const SourceMgr &SM) {
+ const SourceMgr &SM) const {
if (IsPseudo && !Name.equals("@LINE"))
return FileCheckErrorDiagnostic::get(
SM, Name, "invalid pseudo numeric variable '" + Name + "'");
@@ -202,29 +171,24 @@ FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
}
Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber();
- if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber &&
- !NumericVariable->isValueKnownAtMatchTime())
+ if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)
return FileCheckErrorDiagnostic::get(
SM, Name,
- "numeric variable '" + Name +
- "' defined from input on the same line as used");
+ "numeric variable '" + Name + "' defined on the same line as used");
return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);
}
Expected<std::unique_ptr<FileCheckExpressionAST>>
FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
- Optional<size_t> LineNumber,
- FileCheckPatternContext *Context,
- const SourceMgr &SM) {
+ const SourceMgr &SM) const {
if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
// Try to parse as a numeric variable use.
Expected<FileCheckPattern::VariableProperties> ParseVarResult =
parseVariable(Expr, SM);
if (ParseVarResult)
return parseNumericVariableUse(ParseVarResult->Name,
- ParseVarResult->IsPseudo, LineNumber,
- Context, SM);
+ ParseVarResult->IsPseudo, SM);
if (AO == AllowedOperand::LineVar)
return ParseVarResult.takeError();
// Ignore the error and retry parsing as a literal.
@@ -248,10 +212,10 @@ static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
return LeftOp - RightOp;
}
-Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop(
- StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,
- bool IsLegacyLineExpr, Optional<size_t> LineNumber,
- FileCheckPatternContext *Context, const SourceMgr &SM) {
+Expected<std::unique_ptr<FileCheckExpressionAST>>
+FileCheckPattern::parseBinop(StringRef &Expr,
+ std::unique_ptr<FileCheckExpressionAST> LeftOp,
+ bool IsLegacyLineExpr, const SourceMgr &SM) const {
Expr = Expr.ltrim(SpaceChars);
if (Expr.empty())
return std::move(LeftOp);
@@ -282,7 +246,7 @@ Expected<std::unique_ptr<FileCheckExpressionAST>> FileCheckPattern::parseBinop(
AllowedOperand AO =
IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =
- parseNumericOperand(Expr, AO, LineNumber, Context, SM);
+ parseNumericOperand(Expr, AO, SM);
if (!RightOpResult)
return RightOpResult;
@@ -295,54 +259,50 @@ Expected<std::unique_ptr<FileCheckExpressionAST>>
FileCheckPattern::parseNumericSubstitutionBlock(
StringRef Expr,
Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
- bool IsLegacyLineExpr, Optional<size_t> LineNumber,
- FileCheckPatternContext *Context, const SourceMgr &SM) {
- std::unique_ptr<FileCheckExpressionAST> ExpressionAST = nullptr;
- StringRef DefExpr = StringRef();
+ bool IsLegacyLineExpr, const SourceMgr &SM) const {
+ // Parse the numeric variable definition.
DefinedNumericVariable = None;
- // Save variable definition expression if any.
size_t DefEnd = Expr.find(':');
if (DefEnd != StringRef::npos) {
- DefExpr = Expr.substr(0, DefEnd);
- Expr = Expr.substr(DefEnd + 1);
- }
+ StringRef DefExpr = Expr.substr(0, DefEnd);
+ StringRef UseExpr = Expr.substr(DefEnd + 1);
- // Parse the expression itself.
- Expr = Expr.ltrim(SpaceChars);
- if (!Expr.empty()) {
- // The first operand in a legacy @LINE expression is always the @LINE
- // pseudo variable.
- AllowedOperand AO =
- IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
- Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
- parseNumericOperand(Expr, AO, LineNumber, Context, SM);
- while (ParseResult && !Expr.empty()) {
- ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr,
- LineNumber, Context, SM);
- // Legacy @LINE expressions only allow 2 operands.
- if (ParseResult && IsLegacyLineExpr && !Expr.empty())
- return FileCheckErrorDiagnostic::get(
- SM, Expr,
- "unexpected characters at end of expression '" + Expr + "'");
- }
- if (!ParseResult)
- return ParseResult;
- ExpressionAST = std::move(*ParseResult);
- }
+ UseExpr = UseExpr.ltrim(SpaceChars);
+ if (!UseExpr.empty())
+ return FileCheckErrorDiagnostic::get(
+ SM, UseExpr,
+ "unexpected string after variable definition: '" + UseExpr + "'");
- // Parse the numeric variable definition.
- if (DefEnd != StringRef::npos) {
DefExpr = DefExpr.ltrim(SpaceChars);
Expected<FileCheckNumericVariable *> ParseResult =
- parseNumericVariableDefinition(DefExpr, Context, LineNumber,
- ExpressionAST.get(), SM);
-
+ parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);
if (!ParseResult)
return ParseResult.takeError();
DefinedNumericVariable = *ParseResult;
+
+ return nullptr;
}
- return ExpressionAST;
+ // Parse the expression itself.
+ Expr = Expr.ltrim(SpaceChars);
+ // The first operand in a legacy @LINE expression is always the @LINE pseudo
+ // variable.
+ AllowedOperand AO =
+ IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
+ Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
+ parseNumericOperand(Expr, AO, SM);
+ while (ParseResult && !Expr.empty()) {
+ ParseResult =
+ parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, SM);
+ // Legacy @LINE expressions only allow 2 operands.
+ if (ParseResult && IsLegacyLineExpr && !Expr.empty())
+ return FileCheckErrorDiagnostic::get(
+ SM, Expr,
+ "unexpected characters at end of expression '" + Expr + "'");
+ }
+ if (!ParseResult)
+ return ParseResult;
+ return std::move(*ParseResult);
}
bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
@@ -425,15 +385,14 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
continue;
}
- // String and numeric substitution blocks. Pattern substitution blocks come
+ // String and numeric substitution blocks. String substitution blocks come
// in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some
// other regex) and assigns it to the string variable 'foo'. The latter
- // substitutes foo's value. Numeric substitution blocks recognize the same
- // form as string ones, but start with a '#' sign after the double
- // brackets. They also accept a combined form which sets a numeric variable
- // to the evaluation of an expression. Both string and numeric variable
- // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be
- // valid, as this helps catch some common errors.
+ // substitutes foo's value. Numeric substitution blocks work the same way
+ // as string ones, but start with a '#' sign after the double brackets.
+ // Both string and numeric variable names must satisfy the regular
+ // expression "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch
+ // some common errors.
if (PatternStr.startswith("[[")) {
StringRef UnparsedPatternStr = PatternStr.substr(2);
// Find the closing bracket pair ending the match. End is going to be an
@@ -454,7 +413,6 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
PatternStr = UnparsedPatternStr.substr(End + 2);
bool IsDefinition = false;
- bool SubstNeeded = false;
// Whether the substitution block is a legacy use of @LINE with string
// substitution block syntax.
bool IsLegacyLineExpr = false;
@@ -485,7 +443,6 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
bool IsPseudo = ParseVarResult->IsPseudo;
IsDefinition = (VarEndIdx != StringRef::npos);
- SubstNeeded = !IsDefinition;
if (IsDefinition) {
if ((IsPseudo || !MatchStr.consume_front(":"))) {
SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
@@ -520,61 +477,22 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
if (IsNumBlock) {
Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
- IsLegacyLineExpr, LineNumber, Context,
- SM);
+ IsLegacyLineExpr, SM);
if (!ParseResult) {
logAllUnhandledErrors(ParseResult.takeError(), errs());
return true;
}
ExpressionAST = std::move(*ParseResult);
- SubstNeeded = ExpressionAST != nullptr;
if (DefinedNumericVariable) {
IsDefinition = true;
DefName = (*DefinedNumericVariable)->getName();
- }
- if (SubstNeeded)
+ MatchRegexp = StringRef("[0-9]+");
+ } else
SubstStr = MatchStr;
- else
- MatchRegexp = "[0-9]+";
}
- // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].
- if (IsDefinition) {
- RegExStr += '(';
- ++SubstInsertIdx;
-
- if (IsNumBlock) {
- FileCheckNumericVariableMatch NumericVariableDefinition = {
- *DefinedNumericVariable, CurParen};
- NumericVariableDefs[DefName] = NumericVariableDefinition;
- // This store is done here rather than in match() to allow
- // parseNumericVariableUse() to get the pointer to the class instance
- // of the right variable definition corresponding to a given numeric
- // variable use.
- Context->GlobalNumericVariableTable[DefName] =
- *DefinedNumericVariable;
- } else {
- VariableDefs[DefName] = CurParen;
- // Mark string variable as defined to detect collisions between
- // string and numeric variables in parseNumericVariableUse() and
- // defineCmdlineVariables() when the latter is created later than the
- // former. We cannot reuse GlobalVariableTable for this by populating
- // it with an empty string since we would then lose the ability to
- // detect the use of an undefined variable in match().
- Context->DefinedVariableTable[DefName] = true;
- }
-
- ++CurParen;
- }
-
- if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))
- return true;
-
- if (IsDefinition)
- RegExStr += ')';
-
// Handle substitutions: [[foo]] and [[#<foo expr>]].
- if (SubstNeeded) {
+ if (!IsDefinition) {
// Handle substitution of string variables that were defined earlier on
// the same line by emitting a backreference. Expressions do not
// support substituting a numeric variable defined on the same line.
@@ -597,7 +515,37 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
: Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
Substitutions.push_back(Substitution);
}
+ continue;
+ }
+
+ // Handle variable definitions: [[<def>:(...)]] and
+ // [[#(...)<def>:(...)]].
+ if (IsNumBlock) {
+ FileCheckNumericVariableMatch NumericVariableDefinition = {
+ *DefinedNumericVariable, CurParen};
+ NumericVariableDefs[DefName] = NumericVariableDefinition;
+ // This store is done here rather than in match() to allow
+ // parseNumericVariableUse() to get the pointer to the class instance
+ // of the right variable definition corresponding to a given numeric
+ // variable use.
+ Context->GlobalNumericVariableTable[DefName] = *DefinedNumericVariable;
+ } else {
+ VariableDefs[DefName] = CurParen;
+ // Mark the string variable as defined to detect collisions between
+ // string and numeric variables in parseNumericVariableUse() and
+ // DefineCmdlineVariables() when the latter is created later than the
+ // former. We cannot reuse GlobalVariableTable for this by populating
+ // it with an empty string since we would then lose the ability to
+ // detect the use of an undefined variable in match().
+ Context->DefinedVariableTable[DefName] = true;
}
+ RegExStr += '(';
+ ++CurParen;
+
+ if (AddRegExToRegEx(MatchRegexp, CurParen, SM))
+ return true;
+
+ RegExStr += ')';
}
// Handle fixed string matches.
@@ -1797,32 +1745,11 @@ Error FileCheckPatternContext::defineCmdlineVariables(
unsigned I = 0;
Error Errs = Error::success();
std::string CmdlineDefsDiag;
- SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;
- for (StringRef CmdlineDef : CmdlineDefines) {
- std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();
- size_t EqIdx = CmdlineDef.find('=');
- if (EqIdx == StringRef::npos) {
- CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));
- continue;
- }
- // Numeric variable definition.
- if (CmdlineDef[0] == '#') {
- // Append a copy of the command-line definition adapted to use the same
- // format as in the input file to be able to reuse
- // parseNumericSubstitutionBlock.
- CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();
- std::string SubstitutionStr = CmdlineDef;
- SubstitutionStr[EqIdx] = ':';
- CmdlineDefsIndices.push_back(
- std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));
- CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();
- } else {
- CmdlineDefsDiag += DefPrefix;
- CmdlineDefsIndices.push_back(
- std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));
- CmdlineDefsDiag += (CmdlineDef + "\n").str();
- }
- }
+ StringRef Prefix1 = "Global define #";
+ StringRef Prefix2 = ": ";
+ for (StringRef CmdlineDef : CmdlineDefines)
+ CmdlineDefsDiag +=
+ (Prefix1 + Twine(++I) + Prefix2 + CmdlineDef + "\n").str();
// Create a buffer with fake command line content in order to display
// parsing diagnostic with location information and point to the
@@ -1832,10 +1759,14 @@ Error FileCheckPatternContext::defineCmdlineVariables(
StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());
- for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {
- StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,
- CmdlineDefIndices.second);
- if (CmdlineDef.empty()) {
+ SmallVector<StringRef, 4> CmdlineDefsDiagVec;
+ CmdlineDefsDiagRef.split(CmdlineDefsDiagVec, '\n', -1 /*MaxSplit*/,
+ false /*KeepEmpty*/);
+ for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) {
+ unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size();
+ StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart);
+ size_t EqIdx = CmdlineDef.find('=');
+ if (EqIdx == StringRef::npos) {
Errs = joinErrors(
std::move(Errs),
FileCheckErrorDiagnostic::get(
@@ -1845,35 +1776,31 @@ Error FileCheckPatternContext::defineCmdlineVariables(
// Numeric variable definition.
if (CmdlineDef[0] == '#') {
- // Now parse the definition both to check that the syntax is correct and
- // to create the necessary class instance.
- StringRef CmdlineDefExpr = CmdlineDef.substr(1);
- Optional<FileCheckNumericVariable *> DefinedNumericVariable;
- Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionASTResult =
- FileCheckPattern::parseNumericSubstitutionBlock(
- CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);
- if (!ExpressionASTResult) {
- Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError());
+ StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);
+ Expected<FileCheckNumericVariable *> ParseResult =
+ FileCheckPattern::parseNumericVariableDefinition(CmdlineName, this,
+ None, SM);
+ if (!ParseResult) {
+ Errs = joinErrors(std::move(Errs), ParseResult.takeError());
continue;
}
- std::unique_ptr<FileCheckExpressionAST> ExpressionAST =
- std::move(*ExpressionASTResult);
- // Now evaluate the expression whose value this variable should be set
- // to, since the expression of a command-line variable definition should
- // only use variables defined earlier on the command-line. If not, this
- // is an error and we report it.
- Expected<uint64_t> Value = ExpressionAST->eval();
- if (!Value) {
- Errs = joinErrors(std::move(Errs), Value.takeError());
+
+ StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1);
+ uint64_t Val;
+ if (CmdlineVal.getAsInteger(10, Val)) {
+ Errs = joinErrors(std::move(Errs),
+ FileCheckErrorDiagnostic::get(
+ SM, CmdlineVal,
+ "invalid value in numeric variable definition '" +
+ CmdlineVal + "'"));
continue;
}
-
- assert(DefinedNumericVariable && "No variable defined");
- (*DefinedNumericVariable)->setValue(*Value);
+ FileCheckNumericVariable *DefinedNumericVariable = *ParseResult;
+ DefinedNumericVariable->setValue(Val);
// Record this variable definition.
- GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =
- *DefinedNumericVariable;
+ GlobalNumericVariableTable[DefinedNumericVariable->getName()] =
+ DefinedNumericVariable;
} else {
// String variable definition.
std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
@@ -1910,7 +1837,7 @@ Error FileCheckPatternContext::defineCmdlineVariables(
}
GlobalVariableTable.insert(CmdlineNameVal);
// Mark the string variable as defined to detect collisions between
- // string and numeric variables in defineCmdlineVariables when the latter
+ // string and numeric variables in DefineCmdlineVariables when the latter
// is created later than the former. We cannot reuse GlobalVariableTable
// for this by populating it with an empty string since we would then
// lose the ability to detect the use of an undefined variable in
OpenPOWER on IntegriCloud