[FileCheck] Don't diagnose undef vars at parse time

Summary:
Diagnosing use of undefined variables takes place in
parseNumericVariableUse() and printSubstitutions() for numeric variables
but only takes place in printSubstitutions() for string variables. The
reason for the split location of diagnostics is that parsing is not
aware of the clearing of variables due to --enable-var-scope and thus
use of variables cleared in this way can only be catched by
printSubstitutions().

Beyond the code level inconsistency, there is also a user facing
inconsistency since diagnostics look different between the two
functions. While the diagnostic in printSubstitutions is more verbose,
doing the diagnostic there allows to diagnose all undefined variables
rather than just the first one and error out.

This patch create dummy variable definition when encountering a use of
undefined variable so that parsing can proceed and be diagnosed by
printSubstitutions() later. Tests that were testing whether parsing
fails in such case are thus modified accordingly.

Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk

Subscribers: JonChesterfield, rogfer01, hfinkel, kristina, rnk, tra, arichardson, grimar, dblaikie, probinson, llvm-commits, hiraditya

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D64228

llvm-svn: 365219
This commit is contained in:
Thomas Preud'homme 2019-07-05 16:25:33 +00:00
parent 766accd364
commit fe7ac170a7
3 changed files with 26 additions and 9 deletions

View File

@ -156,13 +156,19 @@ FileCheckPattern::parseNumericVariableUse(StringRef &Expr,
// class instance of the corresponding numeric variable definition is stored // class instance of the corresponding numeric variable definition is stored
// in GlobalNumericVariableTable in parsePattern. Therefore, the pointer we // in GlobalNumericVariableTable in parsePattern. Therefore, the pointer we
// get below is for the class instance corresponding to the last definition // get below is for the class instance corresponding to the last definition
// of this variable use. // of this variable use. If we don't find a variable definition we create a
// dummy one so that parsing can continue. All uses of undefined variables,
// whether string or numeric, are then diagnosed in printSubstitutions()
// after failing to match.
auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
if (VarTableIter == Context->GlobalNumericVariableTable.end()) FileCheckNumericVariable *NumericVariable;
return FileCheckErrorDiagnostic::get( if (VarTableIter != Context->GlobalNumericVariableTable.end())
SM, Name, "using undefined numeric variable '" + Name + "'"); NumericVariable = VarTableIter->second;
else {
NumericVariable = Context->makeNumericVariable(0, Name);
Context->GlobalNumericVariableTable[Name] = NumericVariable;
}
FileCheckNumericVariable *NumericVariable = VarTableIter->second;
if (!IsPseudo && NumericVariable->getDefLineNumber() == LineNumber) if (!IsPseudo && NumericVariable->getDefLineNumber() == LineNumber)
return FileCheckErrorDiagnostic::get( return FileCheckErrorDiagnostic::get(
SM, Name, SM, Name,

View File

@ -76,9 +76,15 @@ UNDEF VAR USE
UNDEFVAR: 11 UNDEFVAR: 11
UNDEF-USE-LABEL: UNDEF VAR USE UNDEF-USE-LABEL: UNDEF VAR USE
UNDEF-USE-NEXT: UNDEFVAR: [[#UNDEFVAR]] UNDEF-USE-NEXT: UNDEFVAR: [[#UNDEFVAR]]
UNDEF-USE-MSG: numeric-expression.txt:[[#@LINE-1]]:30: error: using undefined numeric variable 'UNDEFVAR' UNDEF-USE-MSG: numeric-expression.txt:[[#@LINE-1]]:17: error: {{U}}NDEF-USE-NEXT: expected string not found in input
UNDEF-USE-MSG-NEXT: {{U}}NDEF-USE-NEXT: UNDEFVAR: {{\[\[#UNDEFVAR\]\]}} UNDEF-USE-MSG-NEXT: {{U}}NDEF-USE-NEXT: UNDEFVAR: {{\[\[#UNDEFVAR\]\]}}
UNDEF-USE-MSG-NEXT: {{^ \^$}} UNDEF-USE-MSG-NEXT: {{^ \^$}}
UNDEF-USE-MSG-NEXT: numeric-expression.txt:[[#@LINE-6]]:1: note: scanning from here
UNDEF-USE-MSG-NEXT: UNDEFVAR: 11
UNDEF-USE-MSG-NEXT: {{^\^$}}
UNDEF-USE-MSG-NEXT: numeric-expression.txt:[[#@LINE-9]]:1: note: uses undefined variable "UNDEFVAR"
UNDEF-USE-MSG-NEXT: UNDEFVAR: 11
UNDEF-USE-MSG-NEXT: {{^\^$}}
; Numeric expression with unsupported operator. ; Numeric expression with unsupported operator.
RUN: not FileCheck -D#NUMVAR=10 --check-prefix INVAL-OP --input-file %s %s 2>&1 \ RUN: not FileCheck -D#NUMVAR=10 --check-prefix INVAL-OP --input-file %s %s 2>&1 \

View File

@ -257,11 +257,11 @@ TEST_F(FileCheckTest, ParseExpr) {
// Unacceptable variable. // Unacceptable variable.
EXPECT_TRUE(Tester.parseSubstExpect("10VAR")); EXPECT_TRUE(Tester.parseSubstExpect("10VAR"));
EXPECT_TRUE(Tester.parseSubstExpect("@FOO")); EXPECT_TRUE(Tester.parseSubstExpect("@FOO"));
EXPECT_TRUE(Tester.parseSubstExpect("UNDEF"));
// Only valid variable. // Only valid variable.
EXPECT_FALSE(Tester.parseSubstExpect("@LINE")); EXPECT_FALSE(Tester.parseSubstExpect("@LINE"));
EXPECT_FALSE(Tester.parseSubstExpect("FOO")); EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
EXPECT_FALSE(Tester.parseSubstExpect("UNDEF"));
// Use variable defined on same line. // Use variable defined on same line.
EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:]]")); EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:]]"));
@ -471,9 +471,14 @@ TEST_F(FileCheckTest, FileCheckContext) {
P = FileCheckPattern(Check::CheckPlain, &Cxt, 2); P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
Expression = P.parseNumericSubstitutionBlock(LocalNumVarRef, Expression = P.parseNumericSubstitutionBlock(LocalNumVarRef,
DefinedNumericVariable, SM); DefinedNumericVariable, SM);
EXPECT_TRUE(errorToBool(Expression.takeError())); EXPECT_TRUE(bool(Expression));
ExpressionVal = (*Expression)->eval();
EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
EmptyVar = Cxt.getPatternVarValue(EmptyVarStr); EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
EXPECT_TRUE(errorToBool(EmptyVar.takeError())); EXPECT_TRUE(errorToBool(EmptyVar.takeError()));
// Clear again because parseNumericSubstitutionBlock would have created a
// dummy variable and stored it in GlobalNumericVariableTable.
Cxt.clearLocalVars();
// Redefine global variables and check variables are defined again. // Redefine global variables and check variables are defined again.
GlobalDefines.emplace_back(std::string("$GlobalVar=BAR")); GlobalDefines.emplace_back(std::string("$GlobalVar=BAR"));