Reinstate "FileCheck [5/12]: Introduce regular numeric variables"
This reinstates r360578 (git e47362c1ec1ea31b626336cc05822035601c3e57),
reverted in r360653 (git 004393681c25e34e921adccc69ae6378090dee54),
with a fix for the list added in FileCheck.rst to build without error.
Copyright:
- Linaro (changes up to diff 183612 of revision D55940)
- GraphCore (changes in later versions of revision D55940 and
in new revision created off D55940)
Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar,
arichardson, rnk
Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar,
arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60385
llvm-svn: 360665
diff --git a/llvm/unittests/Support/FileCheckTest.cpp b/llvm/unittests/Support/FileCheckTest.cpp
index 2e9caa2..80120ba 100644
--- a/llvm/unittests/Support/FileCheckTest.cpp
+++ b/llvm/unittests/Support/FileCheckTest.cpp
@@ -14,6 +14,57 @@
class FileCheckTest : public ::testing::Test {};
+TEST_F(FileCheckTest, NumericVariable) {
+ FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
+ EXPECT_EQ("FOO", FooVar.getName());
+
+ // Defined variable: getValue returns a value, setValue fails and value
+ // remains unchanged.
+ llvm::Optional<uint64_t> Value = FooVar.getValue();
+ EXPECT_TRUE(Value);
+ EXPECT_EQ(42U, *Value);
+ EXPECT_TRUE(FooVar.setValue(43));
+ Value = FooVar.getValue();
+ EXPECT_TRUE(Value);
+ EXPECT_EQ(42U, *Value);
+
+ // Clearing variable: getValue fails, clearValue again fails.
+ EXPECT_FALSE(FooVar.clearValue());
+ Value = FooVar.getValue();
+ EXPECT_FALSE(Value);
+ EXPECT_TRUE(FooVar.clearValue());
+
+ // Undefined variable: setValue works, getValue returns value set.
+ EXPECT_FALSE(FooVar.setValue(43));
+ Value = FooVar.getValue();
+ EXPECT_TRUE(Value);
+ EXPECT_EQ(43U, *Value);
+}
+
+uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
+
+TEST_F(FileCheckTest, NumExpr) {
+ FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
+ FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &FooVar, 18);
+
+ // Defined variable: eval returns right value, no undefined variable
+ // returned.
+ llvm::Optional<uint64_t> Value = NumExpr.eval();
+ EXPECT_TRUE(Value);
+ EXPECT_EQ(60U, *Value);
+ StringRef UndefVar = NumExpr.getUndefVarName();
+ EXPECT_EQ("", UndefVar);
+
+ // Undefined variable: eval fails, undefined variable returned. We call
+ // getUndefVarName first to check that it can be called without calling
+ // eval() first.
+ FooVar.clearValue();
+ UndefVar = NumExpr.getUndefVarName();
+ EXPECT_EQ("FOO", UndefVar);
+ Value = NumExpr.eval();
+ EXPECT_FALSE(Value);
+}
+
TEST_F(FileCheckTest, ValidVarNameStart) {
EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('a'));
EXPECT_TRUE(FileCheckPattern::isValidVarNameStart('G'));
@@ -90,22 +141,38 @@
EXPECT_EQ(TrailIdx, VarName.size() - 1);
}
+static StringRef bufferize(SourceMgr &SM, StringRef Str) {
+ std::unique_ptr<MemoryBuffer> Buffer =
+ MemoryBuffer::getMemBufferCopy(Str, "TestBuffer");
+ StringRef StrBufferRef = Buffer->getBuffer();
+ SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
+ return StrBufferRef;
+}
+
class ExprTester {
private:
SourceMgr SM;
+ FileCheckRequest Req;
FileCheckPatternContext Context;
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
public:
+ ExprTester() {
+ std::vector<std::string> GlobalDefines;
+ GlobalDefines.emplace_back(std::string("#FOO=42"));
+ Context.defineCmdlineVariables(GlobalDefines, SM);
+ // Call ParsePattern to have @LINE defined.
+ P.ParsePattern("N/A", "CHECK", SM, 1, Req);
+ }
+
bool parseExpect(std::string &VarName, std::string &Trailer) {
+ bool IsPseudo = VarName[0] == '@';
std::string NameTrailer = VarName + Trailer;
- std::unique_ptr<MemoryBuffer> Buffer =
- MemoryBuffer::getMemBufferCopy(NameTrailer, "TestBuffer");
- StringRef NameTrailerRef = Buffer->getBuffer();
- SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
+ StringRef NameTrailerRef = bufferize(SM, NameTrailer);
StringRef VarNameRef = NameTrailerRef.substr(0, VarName.size());
StringRef TrailerRef = NameTrailerRef.substr(VarName.size());
- return P.parseNumericExpression(VarNameRef, TrailerRef, SM) == nullptr;
+ return P.parseNumericExpression(VarNameRef, IsPseudo, TrailerRef, SM) ==
+ nullptr;
}
};
@@ -121,6 +188,14 @@
Trailer = "";
EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
+ // Defined variable.
+ VarName = "FOO";
+ EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
+
+ // Undefined variable.
+ VarName = "UNDEF";
+ EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
+
// Wrong Pseudovar.
VarName = "@FOO";
EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
@@ -153,19 +228,38 @@
GlobalDefines.emplace_back(std::string("FOO=BAR"));
Context.defineCmdlineVariables(GlobalDefines, SM);
- FileCheckPatternSubstitution Substitution =
+ // Substitution of undefined pattern variable fails.
+ FileCheckPatternSubstitution PatternSubstitution =
FileCheckPatternSubstitution(&Context, "VAR404", 42);
- EXPECT_FALSE(Substitution.getResult());
+ EXPECT_FALSE(PatternSubstitution.getResult());
- FileCheckNumExpr NumExpr = FileCheckNumExpr(42);
- Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12);
- llvm::Optional<std::string> Value = Substitution.getResult();
+ // Substitutions of defined pseudo and non-pseudo numeric variables return
+ // the right value.
+ FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
+ FileCheckNumericVariable NVar = FileCheckNumericVariable("@N", 10);
+ FileCheckNumExpr NumExprLine = FileCheckNumExpr(doAdd, &LineVar, 0);
+ FileCheckNumExpr NumExprN = FileCheckNumExpr(doAdd, &NVar, 3);
+ FileCheckPatternSubstitution SubstitutionLine =
+ FileCheckPatternSubstitution(&Context, "@LINE", &NumExprLine, 12);
+ FileCheckPatternSubstitution SubstitutionN =
+ FileCheckPatternSubstitution(&Context, "N", &NumExprN, 30);
+ llvm::Optional<std::string> Value = SubstitutionLine.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("42", *Value);
+ Value = SubstitutionN.getResult();
+ EXPECT_TRUE(Value);
+ EXPECT_EQ("13", *Value);
+ // Substitution of undefined numeric variable fails.
+ LineVar.clearValue();
+ EXPECT_FALSE(SubstitutionLine.getResult());
+ NVar.clearValue();
+ EXPECT_FALSE(SubstitutionN.getResult());
+
+ // Substitution of defined pattern variable returns the right value.
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
- Substitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
- Value = Substitution.getResult();
+ PatternSubstitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
+ Value = PatternSubstitution.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("BAR", *Value);
}
@@ -177,19 +271,32 @@
GlobalDefines.emplace_back(std::string("FOO=BAR"));
Context.defineCmdlineVariables(GlobalDefines, SM);
+ // getUndefVarName() on a pattern variable substitution with an undefined
+ // variable returns that variable.
FileCheckPatternSubstitution Substitution =
FileCheckPatternSubstitution(&Context, "VAR404", 42);
StringRef UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("VAR404", UndefVar);
- FileCheckNumExpr NumExpr = FileCheckNumExpr(42);
+ // getUndefVarName() on a pattern variable substitution with a defined
+ // variable returns an empty string.
+ Substitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
+ UndefVar = Substitution.getUndefVarName();
+ EXPECT_EQ("", UndefVar);
+
+ // getUndefVarName() on a numeric expression substitution with a defined
+ // variable returns an empty string.
+ FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
+ FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &LineVar, 0);
Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12);
UndefVar = Substitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
- Substitution = FileCheckPatternSubstitution(&Context, "FOO", 42);
+ // getUndefVarName() on a numeric expression substitution with an undefined
+ // variable returns that variable.
+ LineVar.clearValue();
UndefVar = Substitution.getUndefVarName();
- EXPECT_EQ("", UndefVar);
+ EXPECT_EQ("@LINE", UndefVar);
}
TEST_F(FileCheckTest, FileCheckContext) {
@@ -197,36 +304,71 @@
std::vector<std::string> GlobalDefines;
SourceMgr SM;
- // Missing equal sign
+ // Missing equal sign.
GlobalDefines.emplace_back(std::string("LocalVar"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
+ GlobalDefines.clear();
+ GlobalDefines.emplace_back(std::string("#LocalNumVar"));
+ EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
- // Empty variable
+ // Empty variable name.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
+ GlobalDefines.clear();
+ GlobalDefines.emplace_back(std::string("#=18"));
+ EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
- // Invalid variable
+ // Invalid variable name.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("18LocalVar=18"));
EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
+ GlobalDefines.clear();
+ GlobalDefines.emplace_back(std::string("#18LocalNumVar=18"));
+ EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
+
+ // Name conflict between pattern and numeric variable.
+ GlobalDefines.clear();
+ GlobalDefines.emplace_back(std::string("LocalVar=18"));
+ GlobalDefines.emplace_back(std::string("#LocalVar=36"));
+ EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
+ Cxt = FileCheckPatternContext();
+ GlobalDefines.clear();
+ GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
+ GlobalDefines.emplace_back(std::string("LocalNumVar=36"));
+ EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
+ Cxt = FileCheckPatternContext();
+
+ // Invalid numeric value for numeric variable.
+ GlobalDefines.clear();
+ GlobalDefines.emplace_back(std::string("#LocalNumVar=x"));
+ EXPECT_TRUE(Cxt.defineCmdlineVariables(GlobalDefines, SM));
// Define local variables from command-line.
GlobalDefines.clear();
GlobalDefines.emplace_back(std::string("LocalVar=FOO"));
GlobalDefines.emplace_back(std::string("EmptyVar="));
+ GlobalDefines.emplace_back(std::string("#LocalNumVar=18"));
bool GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM);
EXPECT_FALSE(GotError);
// Check defined variables are present and undefined is absent.
StringRef LocalVarStr = "LocalVar";
+ StringRef LocalNumVarRef = bufferize(SM, "LocalNumVar");
StringRef EmptyVarStr = "EmptyVar";
StringRef UnknownVarStr = "UnknownVar";
llvm::Optional<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
+ FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt);
+ FileCheckNumExpr *NumExpr =
+ P.parseNumericExpression(LocalNumVarRef, false /*IsPseudo*/, "", SM);
llvm::Optional<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
llvm::Optional<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
EXPECT_TRUE(LocalVar);
EXPECT_EQ(*LocalVar, "FOO");
+ EXPECT_TRUE(NumExpr);
+ llvm::Optional<uint64_t> NumExprVal = NumExpr->eval();
+ EXPECT_TRUE(NumExprVal);
+ EXPECT_EQ(*NumExprVal, 18U);
EXPECT_TRUE(EmptyVar);
EXPECT_EQ(*EmptyVar, "");
EXPECT_FALSE(UnknownVar);
@@ -235,21 +377,46 @@
Cxt.clearLocalVars();
LocalVar = Cxt.getPatternVarValue(LocalVarStr);
EXPECT_FALSE(LocalVar);
+ // Check a numeric expression's evaluation fails if called after clearing of
+ // local variables, if it was created before. This is important because local
+ // variable clearing due to --enable-var-scope happens after numeric
+ // expressions are linked to the numeric variables they use.
+ EXPECT_FALSE(NumExpr->eval());
+ P = FileCheckPattern(Check::CheckPlain, &Cxt);
+ NumExpr =
+ P.parseNumericExpression(LocalNumVarRef, false /*IsPseudo*/, "", SM);
+ EXPECT_FALSE(NumExpr);
EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
EXPECT_FALSE(EmptyVar);
// Redefine global variables and check variables are defined again.
GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));
+ GlobalDefines.emplace_back(std::string("#$GlobalNumVar=36"));
GotError = Cxt.defineCmdlineVariables(GlobalDefines, SM);
EXPECT_FALSE(GotError);
StringRef GlobalVarStr = "$GlobalVar";
+ StringRef GlobalNumVarRef = bufferize(SM, "$GlobalNumVar");
llvm::Optional<StringRef> GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
EXPECT_TRUE(GlobalVar);
EXPECT_EQ(*GlobalVar, "BAR");
+ P = FileCheckPattern(Check::CheckPlain, &Cxt);
+ NumExpr =
+ P.parseNumericExpression(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
+ EXPECT_TRUE(NumExpr);
+ NumExprVal = NumExpr->eval();
+ EXPECT_TRUE(NumExprVal);
+ EXPECT_EQ(*NumExprVal, 36U);
// Clear local variables and check global variables remain defined.
Cxt.clearLocalVars();
GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
EXPECT_TRUE(GlobalVar);
+ P = FileCheckPattern(Check::CheckPlain, &Cxt);
+ NumExpr =
+ P.parseNumericExpression(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
+ EXPECT_TRUE(NumExpr);
+ NumExprVal = NumExpr->eval();
+ EXPECT_TRUE(NumExprVal);
+ EXPECT_EQ(*NumExprVal, 36U);
}
} // namespace