llvm.org GIT mirror llvm / 0e1843c
FileCheck [6/12]: Introduce numeric variable definition Summary: This patch is part of a patch series to add support for FileCheck numeric expressions. This specific patch introduces support for defining numeric variable in a CHECK directive. This commit introduces support for defining numeric variable from a litteral value in the input text. Numeric expressions can then use the variable provided it is on a later line. 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/D60386 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@362705 91177308-0d34-0410-b5e6-96231b3b80d8 Thomas Preud'homme a month ago
8 changed file(s) with 737 addition(s) and 368 deletion(s). Raw diff Collapse all Expand all
570570 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
571571
572572 :program:`FileCheck` also supports numeric substitution blocks that allow
573 checking for numeric values that satisfy a numeric expression constraint based
574 on numeric variables. This allows ``CHECK:`` directives to verify a numeric
575 relation between two numbers, such as the need for consecutive registers to be
576 used.
577
578 The syntax of a numeric substitution block is ``[[#]]``
579 where:
580
581 * ```` is the name of a numeric variable defined on the command line.
573 defining numeric variables and checking for numeric values that satisfy a
574 numeric expression constraint based on those variables via a numeric
575 substitution. This allows ``CHECK:`` directives to verify a numeric relation
576 between two numbers, such as the need for consecutive registers to be used.
577
578 The syntax to define a numeric variable is ``[[#:]]`` where
579 ```` is the name of the numeric variable to define to the matching
580 value.
581
582 For example:
583
584 .. code-block:: llvm
585
586 ; CHECK: mov r[[#REG:]], 42
587
588 would match ``mov r5, 42`` and set ``REG`` to the value ``5``.
589
590 The syntax of a numeric substitution is ``[[#]]`` where:
591
592 * ```` is the name of a defined numeric variable.
582593
583594 * ```` is an optional numeric operation to perform on the value of
584595 ````. Currently supported numeric operations are ``+`` and ``-``.
589600
590601 Spaces are accepted before, after and between any of these elements.
591602
592 Unlike string substitution blocks, numeric substitution blocks only introduce
593 numeric substitutions which substitute a numeric expression for its value.
594603 For example:
595604
596605 .. code-block:: llvm
597606
598 ; CHECK: add r[[#REG]], r[[#REG]], r[[#REG+1]]
599
600 The above example would match the line:
607 ; CHECK: load r[[#REG:]], [r0]
608 ; CHECK: load r[[#REG+1]], [r1]
609
610 The above example would match the text:
601611
602612 .. code-block:: gas
603613
604 add r5, r5, r6
605
606 but would not match the line:
614 load r5, [r0]
615 load r6, [r1]
616
617 but would not match the text:
607618
608619 .. code-block:: gas
609620
610 add r5, r5, r7
621 load r5, [r0]
622 load r7, [r1]
611623
612624 due to ``7`` being unequal to ``5 + 1``.
613625
614626 The ``--enable-var-scope`` option has the same effect on numeric variables as
615627 on string variables.
628
629 Important note: In its current implementation, a numeric expression cannot use
630 a numeric variable defined on the same line.
616631
617632 FileCheck Pseudo Numeric Variables
618633 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
623638 line numbers in the same file, which have to be updated whenever line numbers
624639 change due to text addition or deletion.
625640
626 To support this case, FileCheck understands the ``@LINE`` pseudo numeric
627 variable which evaluates to the line number of the CHECK pattern where it is
628 found.
641 To support this case, FileCheck numeric expressions understand the ``@LINE``
642 pseudo numeric variable which evaluates to the line number of the CHECK pattern
643 where it is found.
629644
630645 This way match patterns can be put near the relevant test lines and include
631646 relative line number references, for example:
4040 //===----------------------------------------------------------------------===//
4141
4242 /// Class representing a numeric variable with a given value in a numeric
43 /// expression.
43 /// expression. Each definition of a variable gets its own instance of this
44 /// class. Variable uses share the same instance as their respective
45 /// definition.
4446 class FileCheckNumericVariable {
4547 private:
4648 /// Name of the numeric variable.
4951 /// Value of numeric variable, if defined, or None otherwise.
5052 Optional Value;
5153
52 public:
54 /// Line number where this variable is defined. Used to determine whether a
55 /// variable is defined on the same line as a given use.
56 size_t DefLineNumber;
57
58 public:
59 /// Constructor for a variable \p Name defined at line \p DefLineNumber.
60 FileCheckNumericVariable(size_t DefLineNumber, StringRef Name)
61 : Name(Name), DefLineNumber(DefLineNumber) {}
62
5363 /// Constructor for numeric variable \p Name with a known \p Value at parse
5464 /// time (e.g. the @LINE numeric variable).
5565 FileCheckNumericVariable(StringRef Name, uint64_t Value)
56 : Name(Name), Value(Value) {}
66 : Name(Name), Value(Value), DefLineNumber(0) {}
5767
5868 /// \returns name of that numeric variable.
5969 StringRef getName() const { return Name; }
6878 /// Clears value of this numeric variable. \returns whether the variable was
6979 /// already undefined.
7080 bool clearValue();
81
82 /// \returns the line number where this variable is defined.
83 size_t getDefLineNumber() { return DefLineNumber; }
7184 };
7285
7386 /// Type of functions evaluating a given binary operation.
247260
248261 /// When matching a given pattern, this holds the pointers to the classes
249262 /// representing the last definitions of numeric variables defined in
250 /// previous patterns. Earlier definition of the variables, if any, have
251 /// their own class instance not referenced by this table.
263 /// previous patterns. Earlier definitions of the variables, if any, have
264 /// their own class instance not referenced by this table. When matching a
265 /// pattern all definitions for that pattern are recorded in the
266 /// NumericVariableDefs table in the FileCheckPattern instance of that
267 /// pattern.
252268 StringMap GlobalNumericVariableTable;
253269
254270 /// Vector holding pointers to all parsed numeric expressions. Used to
291307
292308 /// Makes a new numeric variable and registers it for destruction when the
293309 /// context is destroyed.
294 FileCheckNumericVariable *makeNumericVariable(StringRef Name, uint64_t Value);
310 template
311 FileCheckNumericVariable *makeNumericVariable(Types... args);
295312
296313 /// Makes a new string substitution and registers it for destruction when the
297314 /// context is destroyed.
324341 /// and the value of numeric expression "N+1" at offset 6.
325342 std::vector Substitutions;
326343
327 /// Maps names of string variables defined in a pattern to the parenthesized
328 /// capture numbers of their last definition.
329 ///
330 /// E.g. for the pattern "foo[[bar:.*]]baz[[bar]]quux[[bar:.*]]",
331 /// VariableDefs will map "bar" to 2 corresponding to the second definition
332 /// of "bar".
344 /// Maps names of string variables defined in a pattern to the number of
345 /// their parenthesis group in RegExStr capturing their last definition.
346 ///
347 /// E.g. for the pattern "foo[[bar:.*]]baz([[bar]][[QUUX]][[bar:.*]])",
348 /// RegExStr will be "foo(.*)baz(\1(.*))" where is
349 /// the value captured for QUUX on the earlier line where it was defined, and
350 /// VariableDefs will map "bar" to the third parenthesis group which captures
351 /// the second definition of "bar".
333352 ///
334353 /// Note: uses std::map rather than StringMap to be able to get the key when
335354 /// iterating over values.
336355 std::map VariableDefs;
356
357 /// Structure representing the definition of a numeric variable in a pattern.
358 /// It holds the pointer to the class representing the numeric variable whose
359 /// value is being defined and the number of the parenthesis group in
360 /// RegExStr to capture that value.
361 struct FileCheckNumExprMatch {
362 /// Pointer to class representing the numeric variable whose value is being
363 /// defined.
364 FileCheckNumericVariable *DefinedNumericVariable;
365
366 /// Number of the parenthesis group in RegExStr that captures the value of
367 /// this numeric variable definition.
368 unsigned CaptureParenGroup;
369 };
370
371 /// Holds the number of the parenthesis group in RegExStr and pointer to the
372 /// corresponding FileCheckNumericVariable class instance of all numeric
373 /// variable definitions. Used to set the matched value of all those
374 /// variables.
375 StringMap NumericVariableDefs;
337376
338377 /// Pointer to a class instance holding the global state shared by all
339378 /// patterns:
345384
346385 Check::FileCheckType CheckTy;
347386
348 /// Contains the number of line this pattern is in.
349 unsigned LineNumber;
350
351 public:
352 explicit FileCheckPattern(Check::FileCheckType Ty,
353 FileCheckPatternContext *Context)
354 : Context(Context), CheckTy(Ty) {}
387 /// Line number for this CHECK pattern. Used to determine whether a variable
388 /// definition is made on an earlier line to the one with this CHECK.
389 size_t LineNumber;
390
391 public:
392 FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context,
393 size_t Line)
394 : Context(Context), CheckTy(Ty), LineNumber(Line) {}
355395
356396 /// \returns the location in source code.
357397 SMLoc getLoc() const { return PatternLoc; }
362402
363403 /// \returns whether \p C is a valid first character for a variable name.
364404 static bool isValidVarNameStart(char C);
365 /// Verifies that the string at the start of \p Str is a well formed
366 /// variable. \returns false if it is and sets \p IsPseudo to indicate if it
367 /// is a pseudo variable and \p TrailIdx to the position of the last
368 /// character that is part of the variable name. Otherwise, only
369 /// \returns true.
370 static bool parseVariable(StringRef Str, bool &IsPseudo, unsigned &TrailIdx);
371 /// Parses a numeric substitution involving (pseudo if \p IsPseudo is true)
372 /// variable \p Name with the string corresponding to the operation being
373 /// performed in \p Trailer. \returns the class representing the numeric
374 /// expression being substituted or nullptr if parsing fails, in which case
375 /// errors are reported on \p SM.
376 FileCheckNumExpr *parseNumericSubstitution(StringRef Name, bool IsPseudo,
377 StringRef Trailer,
378 const SourceMgr &SM) const;
405 /// Parses the string at the start of \p Str for a variable name and \returns
406 /// whether the variable name is ill-formed. If parsing succeeded, sets
407 /// \p IsPseudo to indicate if it is a pseudo variable, sets \p Name to the
408 /// parsed variable name and strips \p Str from the variable name.
409 static bool parseVariable(StringRef &Str, StringRef &Name, bool &IsPseudo);
410 /// Parses \p Expr for the definition of a numeric variable, returning an
411 /// error if \p Context already holds a string variable with the same name.
412 /// \returns whether parsing fails, in which case errors are reported on
413 /// \p SM. Otherwise, sets \p Name to the name of the parsed numeric
414 /// variable.
415 static bool parseNumericVariableDefinition(StringRef &Expr, StringRef &Name,
416 FileCheckPatternContext *Context,
417 const SourceMgr &SM);
418 /// Parses \p Expr for a numeric substitution block. \returns the class
419 /// representing the AST of the numeric expression whose value must be
420 /// substituted, or nullptr if parsing fails, in which case errors are
421 /// reported on \p SM. Sets \p DefinedNumericVariable to point to the class
422 /// representing the numeric variable defined in this numeric substitution
423 /// block, or nullptr if this block does not define any variable.
424 FileCheckNumExpr *parseNumericSubstitutionBlock(
425 StringRef Expr, FileCheckNumericVariable *&DefinedNumericVariable,
426 const SourceMgr &SM) const;
379427 /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
380428 /// instance accordingly.
381429 ///
382430 /// \p Prefix provides which prefix is being matched, \p Req describes the
383431 /// global options that influence the parsing such as whitespace
384 /// canonicalization, \p SM provides the SourceMgr used for error reports,
385 /// and \p LineNumber is the line number in the input file from which the
386 /// pattern string was read. \returns true in case of an error, false
387 /// otherwise.
388 bool ParsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
389 unsigned LineNumber, const FileCheckRequest &Req);
432 /// canonicalization, \p SM provides the SourceMgr used for error reports.
433 /// \returns true in case of an error, false otherwise.
434 bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
435 const FileCheckRequest &Req);
390436 /// Matches the pattern string against the input buffer \p Buffer
391437 ///
392438 /// \returns the position that is matched or npos if there is no match. If
395441 ///
396442 /// The GlobalVariableTable StringMap in the FileCheckPatternContext class
397443 /// instance provides the current values of FileCheck string variables and
398 /// is updated if this match defines new values.
399 size_t match(StringRef Buffer, size_t &MatchLen) const;
444 /// is updated if this match defines new values. Likewise, the
445 /// GlobalNumericVariableTable StringMap in the same class provides the
446 /// current values of FileCheck numeric variables and is updated if this
447 /// match defines new numeric values.
448 size_t match(StringRef Buffer, size_t &MatchLen, const SourceMgr &SM) const;
400449 /// Prints the value of successful substitutions or the name of the undefined
401450 /// string or numeric variable preventing a successful substitution.
402451 void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
426475 /// \returns the offset of the closing sequence within Str, or npos if it
427476 /// was not found.
428477 size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
478
479 /// Parses \p Expr for the use of a numeric variable. \returns the pointer to
480 /// the class instance representing that variable if successful, or nullptr
481 /// otherwise, in which case errors are reported on \p SM.
482 FileCheckNumericVariable *parseNumericVariableUse(StringRef &Expr,
483 const SourceMgr &SM) const;
484 /// Parses \p Expr for a binary operation.
485 /// \returns the class representing the binary operation of the numeric
486 /// expression, or nullptr if parsing fails, in which case errors are
487 /// reported on \p SM.
488 FileCheckNumExpr *parseBinop(StringRef &Expr, const SourceMgr &SM) const;
429489 };
430490
431491 //===----------------------------------------------------------------------===//
3838 }
3939
4040 Optional FileCheckNumExpr::eval() const {
41 Optional LeftOp = this->LeftOp->getValue();
41 assert(LeftOp && "Evaluating an empty numeric expression");
42 Optional LeftOpValue = LeftOp->getValue();
4243 // Variable is undefined.
43 if (!LeftOp)
44 if (!LeftOpValue)
4445 return None;
45 return EvalBinop(*LeftOp, RightOp);
46 return EvalBinop(*LeftOpValue, RightOp);
4647 }
4748
4849 StringRef FileCheckNumExpr::getUndefVarName() const {
8384 return C == '_' || isalpha(C);
8485 }
8586
86 bool FileCheckPattern::parseVariable(StringRef Str, bool &IsPseudo,
87 unsigned &TrailIdx) {
87 bool FileCheckPattern::parseVariable(StringRef &Str, StringRef &Name,
88 bool &IsPseudo) {
8889 if (Str.empty())
8990 return true;
9091
106107 ParsedOneChar = true;
107108 }
108109
109 TrailIdx = I;
110 Name = Str.take_front(I);
111 Str = Str.substr(I);
110112 return false;
111113 }
112114
121123 return C;
122124 }
123125
124 static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
125 return LeftOp + RightOp;
126 }
127 static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
128 return LeftOp - RightOp;
129 }
130
131 FileCheckNumExpr *
132 FileCheckPattern::parseNumericSubstitution(StringRef Name, bool IsPseudo,
133 StringRef Trailer,
134 const SourceMgr &SM) const {
126 bool FileCheckPattern::parseNumericVariableDefinition(
127 StringRef &Expr, StringRef &Name, FileCheckPatternContext *Context,
128 const SourceMgr &SM) {
129 bool IsPseudo;
130 if (parseVariable(Expr, Name, IsPseudo)) {
131 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
132 "invalid variable name");
133 return true;
134 }
135
136 if (IsPseudo) {
137 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
138 "definition of pseudo numeric variable unsupported");
139 return true;
140 }
141
142 // Detect collisions between string and numeric variables when the latter
143 // is created later than the former.
144 if (Context->DefinedVariableTable.find(Name) !=
145 Context->DefinedVariableTable.end()) {
146 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
147 "string variable with name '" + Name + "' already exists");
148 return true;
149 }
150
151 return false;
152 }
153
154 FileCheckNumericVariable *
155 FileCheckPattern::parseNumericVariableUse(StringRef &Expr,
156 const SourceMgr &SM) const {
157 bool IsPseudo;
158 StringRef Name;
159 if (parseVariable(Expr, Name, IsPseudo)) {
160 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
161 "invalid variable name");
162 return nullptr;
163 }
164
135165 if (IsPseudo && !Name.equals("@LINE")) {
136166 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
137167 "invalid pseudo numeric variable '" + Name + "'");
138168 return nullptr;
139169 }
140170
141 // This method is indirectly called from ParsePattern for all numeric
171 // This method is indirectly called from parsePattern for all numeric
142172 // variable definitions and uses in the order in which they appear in the
143173 // CHECK pattern. For each definition, the pointer to the class instance of
144174 // the corresponding numeric variable definition is stored in
151181 return nullptr;
152182 }
153183
154 FileCheckNumericVariable *LeftOp = VarTableIter->second;
184 FileCheckNumericVariable *NumericVariable = VarTableIter->second;
185 if (!IsPseudo && NumericVariable->getDefLineNumber() == LineNumber) {
186 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
187 "numeric variable '" + Name +
188 "' defined on the same line as used");
189 return nullptr;
190 }
191
192 return NumericVariable;
193 }
194
195 static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
196 return LeftOp + RightOp;
197 }
198
199 static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
200 return LeftOp - RightOp;
201 }
202
203 FileCheckNumExpr *FileCheckPattern::parseBinop(StringRef &Expr,
204 const SourceMgr &SM) const {
205 FileCheckNumericVariable *LeftOp = parseNumericVariableUse(Expr, SM);
206 if (!LeftOp) {
207 // Error reporting done in parseNumericVariableUse().
208 return nullptr;
209 }
155210
156211 // Check if this is a supported operation and select a function to perform
157212 // it.
158 Trailer = Trailer.ltrim(SpaceChars);
159 if (Trailer.empty()) {
213 Expr = Expr.ltrim(SpaceChars);
214 if (Expr.empty())
160215 return Context->makeNumExpr(add, LeftOp, 0);
161 }
162 SMLoc OpLoc = SMLoc::getFromPointer(Trailer.data());
163 char Operator = popFront(Trailer);
216 SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());
217 char Operator = popFront(Expr);
164218 binop_eval_t EvalBinop;
165219 switch (Operator) {
166220 case '+':
177231 }
178232
179233 // Parse right operand.
180 Trailer = Trailer.ltrim(SpaceChars);
181 if (Trailer.empty()) {
182 SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
234 Expr = Expr.ltrim(SpaceChars);
235 if (Expr.empty()) {
236 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
183237 "missing operand in numeric expression");
184238 return nullptr;
185239 }
186240 uint64_t RightOp;
187 if (Trailer.consumeInteger(10, RightOp)) {
188 SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
189 "invalid offset in numeric expression '" + Trailer + "'");
241 if (Expr.consumeInteger(10, RightOp)) {
242 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
243 "invalid offset in numeric expression '" + Expr + "'");
190244 return nullptr;
191245 }
192 Trailer = Trailer.ltrim(SpaceChars);
193 if (!Trailer.empty()) {
194 SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
246 Expr = Expr.ltrim(SpaceChars);
247 if (!Expr.empty()) {
248 SM.PrintMessage(SMLoc::getFromPointer(Expr.data()), SourceMgr::DK_Error,
195249 "unexpected characters at end of numeric expression '" +
196 Trailer + "'");
250 Expr + "'");
197251 return nullptr;
198252 }
199253
200254 return Context->makeNumExpr(EvalBinop, LeftOp, RightOp);
201255 }
202256
203 bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix,
204 SourceMgr &SM, unsigned LineNumber,
257 FileCheckNumExpr *FileCheckPattern::parseNumericSubstitutionBlock(
258 StringRef Expr, FileCheckNumericVariable *&DefinedNumericVariable,
259 const SourceMgr &SM) const {
260 // Parse the numeric variable definition.
261 DefinedNumericVariable = nullptr;
262 size_t DefEnd = Expr.find(':');
263 if (DefEnd != StringRef::npos) {
264 StringRef DefExpr = Expr.substr(0, DefEnd);
265 StringRef UseExpr = Expr = Expr.substr(DefEnd + 1);
266
267 DefExpr = DefExpr.ltrim(SpaceChars);
268 StringRef Name;
269 if (parseNumericVariableDefinition(DefExpr, Name, Context, SM)) {
270 // Invalid variable definition. Error reporting done in parsing function.
271 return nullptr;
272 }
273
274 DefinedNumericVariable =
275 Context->makeNumericVariable(this->LineNumber, Name);
276
277 DefExpr = DefExpr.ltrim(SpaceChars);
278 if (!DefExpr.empty()) {
279 SM.PrintMessage(SMLoc::getFromPointer(DefExpr.data()),
280 SourceMgr::DK_Error,
281 "invalid numeric variable definition");
282 return nullptr;
283 }
284 UseExpr = UseExpr.ltrim(SpaceChars);
285 if (!UseExpr.empty()) {
286 SM.PrintMessage(
287 SMLoc::getFromPointer(UseExpr.data()), SourceMgr::DK_Error,
288 "unexpected string after variable definition: '" + UseExpr + "'");
289 return nullptr;
290 }
291 return Context->makeNumExpr(add, nullptr, 0);
292 }
293
294 // Parse the numeric expression itself.
295 Expr = Expr.ltrim(SpaceChars);
296 return parseBinop(Expr, SM);
297 }
298
299 bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
300 SourceMgr &SM,
205301 const FileCheckRequest &Req) {
206302 bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
207303
208 this->LineNumber = LineNumber;
209304 PatternLoc = SMLoc::getFromPointer(PatternStr.data());
210305
211306 // Create fake @LINE pseudo variable definition.
291386 // String and numeric substitution blocks. String substitution blocks come
292387 // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some
293388 // other regex) and assigns it to the string variable 'foo'. The latter
294 // substitutes foo's value. Numeric substitution blocks start with a
295 // '#' sign after the double brackets and only have the substitution form.
296 // Both string and numeric variables must satisfy the regular expression
297 // "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch some common
298 // errors.
389 // substitutes foo's value. Numeric substitution blocks work the same way
390 // as string ones, but start with a '#' sign after the double brackets.
391 // Both string and numeric variable names must satisfy the regular
392 // expression "[a-zA-Z_][0-9a-zA-Z_]*" to be valid, as this helps catch
393 // some common errors.
299394 if (PatternStr.startswith("[[")) {
300395 StringRef UnparsedPatternStr = PatternStr.substr(2);
301396 // Find the closing bracket pair ending the match. End is going to be an
315410 // index of the first unparsed character.
316411 PatternStr = UnparsedPatternStr.substr(End + 2);
317412
318 size_t VarEndIdx = MatchStr.find(":");
319 if (IsNumBlock)
320 MatchStr = MatchStr.ltrim(SpaceChars);
321 else {
413 bool IsDefinition = false;
414 StringRef DefName;
415 StringRef SubstStr;
416 StringRef MatchRegexp;
417 size_t SubstInsertIdx = RegExStr.size();
418
419 // Parse string variable or legacy numeric expression.
420 if (!IsNumBlock) {
421 size_t VarEndIdx = MatchStr.find(":");
322422 size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
323423 if (SpacePos != StringRef::npos) {
324424 SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos),
325425 SourceMgr::DK_Error, "unexpected whitespace");
326426 return true;
327427 }
328 }
329
330 // Get the variable name (e.g. "foo") and verify it is well formed.
331 bool IsPseudo;
332 unsigned TrailIdx;
333 if (parseVariable(MatchStr, IsPseudo, TrailIdx)) {
334 SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
335 SourceMgr::DK_Error, "invalid variable name");
336 return true;
337 }
338
339 size_t SubstInsertIdx = RegExStr.size();
340 FileCheckNumExpr *NumExpr;
341
342 StringRef Name = MatchStr.substr(0, TrailIdx);
343 StringRef Trailer = MatchStr.substr(TrailIdx);
344 bool IsVarDef = (VarEndIdx != StringRef::npos);
345
346 if (IsVarDef) {
347 if (IsPseudo || !Trailer.consume_front(":")) {
428
429 // Get the name (e.g. "foo") and verify it is well formed.
430 bool IsPseudo;
431 StringRef Name;
432 StringRef OrigMatchStr = MatchStr;
433 if (parseVariable(MatchStr, Name, IsPseudo)) {
348434 SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
349 SourceMgr::DK_Error,
350 "invalid name in string variable definition");
435 SourceMgr::DK_Error, "invalid variable name");
351436 return true;
352437 }
353438
354 // Detect collisions between string and numeric variables when the
355 // former is created later than the latter.
356 if (Context->GlobalNumericVariableTable.find(Name) !=
357 Context->GlobalNumericVariableTable.end()) {
358 SM.PrintMessage(
359 SMLoc::getFromPointer(MatchStr.data()), SourceMgr::DK_Error,
360 "numeric variable with name '" + Name + "' already exists");
361 return true;
439 IsDefinition = (VarEndIdx != StringRef::npos);
440 if (IsDefinition) {
441 if ((IsPseudo || !MatchStr.consume_front(":"))) {
442 SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
443 SourceMgr::DK_Error,
444 "invalid name in string variable definition");
445 return true;
446 }
447
448 // Detect collisions between string and numeric variables when the
449 // former is created later than the latter.
450 if (Context->GlobalNumericVariableTable.find(Name) !=
451 Context->GlobalNumericVariableTable.end()) {
452 SM.PrintMessage(
453 SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
454 "numeric variable with name '" + Name + "' already exists");
455 return true;
456 }
457 DefName = Name;
458 MatchRegexp = MatchStr;
459 } else {
460 if (IsPseudo) {
461 MatchStr = OrigMatchStr;
462 IsNumBlock = true;
463 } else
464 SubstStr = Name;
362465 }
363466 }
364467
365 if (IsNumBlock || (!IsVarDef && IsPseudo)) {
366 NumExpr = parseNumericSubstitution(Name, IsPseudo, Trailer, SM);
468 // Parse numeric substitution block.
469 FileCheckNumExpr *NumExpr;
470 FileCheckNumericVariable *DefinedNumericVariable;
471 if (IsNumBlock) {
472 NumExpr =
473 parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, SM);
367474 if (NumExpr == nullptr)
368475 return true;
369 IsNumBlock = true;
476 if (DefinedNumericVariable) {
477 IsDefinition = true;
478 DefName = DefinedNumericVariable->getName();
479 MatchRegexp = StringRef("[0-9]+");
480 } else
481 SubstStr = MatchStr;
370482 }
371483
372484 // Handle substitutions: [[foo]] and [[#]].
373 if (!IsVarDef) {
485 if (!IsDefinition) {
374486 // Handle substitution of string variables that were defined earlier on
375 // the same line by emitting a backreference.
376 if (!IsNumBlock && VariableDefs.find(Name) != VariableDefs.end()) {
377 unsigned CaptureParen = VariableDefs[Name];
378 if (CaptureParen < 1 || CaptureParen > 9) {
379 SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
487 // the same line by emitting a backreference. Numeric expressions do
488 // not support substituting a numeric variable defined on the same
489 // line.
490 if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) {
491 unsigned CaptureParenGroup = VariableDefs[SubstStr];
492 if (CaptureParenGroup < 1 || CaptureParenGroup > 9) {
493 SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()),
380494 SourceMgr::DK_Error,
381495 "Can't back-reference more than 9 variables");
382496 return true;
383497 }
384 AddBackrefToRegEx(CaptureParen);
498 AddBackrefToRegEx(CaptureParenGroup);
385499 } else {
386500 // Handle substitution of string variables ([[]]) defined in
387501 // previous CHECK patterns, and substitution of numeric expressions.
388502 FileCheckSubstitution *Substitution =
389503 IsNumBlock
390 ? Context->makeNumericSubstitution(MatchStr, NumExpr,
504 ? Context->makeNumericSubstitution(SubstStr, NumExpr,
391505 SubstInsertIdx)
392 : Context->makeStringSubstitution(MatchStr, SubstInsertIdx);
506 : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
393507 Substitutions.push_back(Substitution);
394508 }
395509 continue;
396510 }
397511
398 // Handle variable definitions: [[foo:.*]].
399 VariableDefs[Name] = CurParen;
512 // Handle variable definitions: [[:(...)]] and
513 // [[#(...):(...)]].
514 if (IsNumBlock) {
515 FileCheckNumExprMatch NumExprDef = {DefinedNumericVariable, CurParen};
516 NumericVariableDefs[DefName] = NumExprDef;
517 // This store is done here rather than in match() to allow
518 // parseNumericVariableUse() to get the pointer to the class instance
519 // of the right variable definition corresponding to a given numeric
520 // variable use.
521 Context->GlobalNumericVariableTable[DefName] = DefinedNumericVariable;
522 } else {
523 VariableDefs[DefName] = CurParen;
524 // Mark the string variable as defined to detect collisions between
525 // string and numeric variables in parseNumericVariableUse() and
526 // DefineCmdlineVariables() when the latter is created later than the
527 // former. We cannot reuse GlobalVariableTable for this by populating
528 // it with an empty string since we would then lose the ability to
529 // detect the use of an undefined variable in match().
530 Context->DefinedVariableTable[DefName] = true;
531 }
400532 RegExStr += '(';
401533 ++CurParen;
402534
403 if (AddRegExToRegEx(Trailer, CurParen, SM))
535 if (AddRegExToRegEx(MatchRegexp, CurParen, SM))
404536 return true;
405537
406538 RegExStr += ')';
443575 RegExStr += Backref;
444576 }
445577
446 size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen) const {
578 size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
579 const SourceMgr &SM) const {
447580 // If this is the EOF pattern, match it immediately.
448581 if (CheckTy == Check::CheckEOF) {
449582 MatchLen = 0;
498631 assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
499632 Context->GlobalVariableTable[VariableDef.first] =
500633 MatchInfo[VariableDef.second];
634 }
635
636 // If this defines any numeric variables, remember their values.
637 for (const auto &NumericVariableDef : NumericVariableDefs) {
638 const FileCheckNumExprMatch &NumericVariableMatch =
639 NumericVariableDef.getValue();
640 unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup;
641 assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error");
642 FileCheckNumericVariable *DefinedNumericVariable =
643 NumericVariableMatch.DefinedNumericVariable;
644
645 StringRef MatchedValue = MatchInfo[CaptureParenGroup];
646 uint64_t Val;
647 if (MatchedValue.getAsInteger(10, Val)) {
648 SM.PrintMessage(SMLoc::getFromPointer(MatchedValue.data()),
649 SourceMgr::DK_Error, "Unable to represent numeric value");
650 }
651 if (DefinedNumericVariable->setValue(Val))
652 assert(false && "Numeric variable redefined");
501653 }
502654
503655 // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
642794 return NumExprs.back().get();
643795 }
644796
797 template
645798 FileCheckNumericVariable *
646 FileCheckPatternContext::makeNumericVariable(StringRef Name, uint64_t Value) {
799 FileCheckPatternContext::makeNumericVariable(Types... args) {
647800 NumericVariables.push_back(
648 llvm::make_unique(Name, Value));
801 llvm::make_unique(args...));
649802 return NumericVariables.back().get();
650803 }
651804
9401093 SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
9411094
9421095 ImplicitNegativeChecks.push_back(
943 FileCheckPattern(Check::CheckNot, &PatternContext));
944 ImplicitNegativeChecks.back().ParsePattern(PatternInBuffer,
945 "IMPLICIT-CHECK", SM, 0, Req);
1096 FileCheckPattern(Check::CheckNot, &PatternContext, 0));
1097 ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,
1098 "IMPLICIT-CHECK", SM, Req);
9461099 }
9471100
9481101 std::vector DagNotMatches = ImplicitNegativeChecks;
10031156 SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
10041157
10051158 // Parse the pattern.
1006 FileCheckPattern P(CheckTy, &PatternContext);
1007 if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber, Req))
1159 FileCheckPattern P(CheckTy, &PatternContext, LineNumber);
1160 if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req))
10081161 return true;
10091162
10101163 // Verify that CHECK-LABEL lines do not define or use variables
10481201 // prefix as a filler for the error message.
10491202 if (!DagNotMatches.empty()) {
10501203 CheckStrings.emplace_back(
1051 FileCheckPattern(Check::CheckEOF, &PatternContext),
1204 FileCheckPattern(Check::CheckEOF, &PatternContext, LineNumber + 1),
10521205 *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
10531206 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
10541207 }
12221375 StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
12231376 size_t CurrentMatchLen;
12241377 // get a match at current start point
1225 size_t MatchPos = Pat.match(MatchBuffer, CurrentMatchLen);
1378 size_t MatchPos = Pat.match(MatchBuffer, CurrentMatchLen, SM);
12261379 if (i == 1)
12271380 FirstMatchPos = LastPos + MatchPos;
12281381
13431496 assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
13441497
13451498 size_t MatchLen = 0;
1346 size_t Pos = Pat->match(Buffer, MatchLen);
1499 size_t Pos = Pat->match(Buffer, MatchLen, SM);
13471500
13481501 if (Pos == StringRef::npos) {
13491502 PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
14031556 // CHECK-DAG group.
14041557 for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
14051558 StringRef MatchBuffer = Buffer.substr(MatchPos);
1406 size_t MatchPosBuf = Pat.match(MatchBuffer, MatchLen);
1559 size_t MatchPosBuf = Pat.match(MatchBuffer, MatchLen, SM);
14071560 // With a group of CHECK-DAGs, a single mismatching means the match on
14081561 // that group of CHECK-DAGs fails immediately.
14091562 if (MatchPosBuf == StringRef::npos) {
15671720 for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) {
15681721 unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size();
15691722 StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart);
1570 if (CmdlineDef.find('=') == StringRef::npos) {
1723 size_t EqIdx = CmdlineDef.find('=');
1724 if (EqIdx == StringRef::npos) {
15711725 SM.PrintMessage(SMLoc::getFromPointer(CmdlineDef.data()),
15721726 SourceMgr::DK_Error,
15731727 "Missing equal sign in global definition");
15771731
15781732 // Numeric variable definition.
15791733 if (CmdlineDef[0] == '#') {
1580 bool IsPseudo;
1581 unsigned TrailIdx;
1582 size_t EqIdx = CmdlineDef.find('=');
15831734 StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);
1584 if (FileCheckPattern::parseVariable(CmdlineName, IsPseudo, TrailIdx) ||
1585 IsPseudo || TrailIdx != CmdlineName.size() || CmdlineName.empty()) {
1586 SM.PrintMessage(SMLoc::getFromPointer(CmdlineName.data()),
1587 SourceMgr::DK_Error,
1588 "invalid name in numeric variable definition '" +
1589 CmdlineName + "'");
1735 StringRef VarName;
1736 SMLoc CmdlineNameLoc = SMLoc::getFromPointer(CmdlineName.data());
1737 bool ParseError = FileCheckPattern::parseNumericVariableDefinition(
1738 CmdlineName, VarName, this, SM);
1739 // Check that CmdlineName starts with a valid numeric variable to be
1740 // defined and that it is not followed that anything. That second check
1741 // detects cases like "FOO+2" in a "FOO+2=10" definition.
1742 if (ParseError || !CmdlineName.empty()) {
1743 if (!ParseError)
1744 SM.PrintMessage(CmdlineNameLoc, SourceMgr::DK_Error,
1745 "invalid variable name");
15901746 ErrorFound = true;
15911747 continue;
15921748 }
15931749
15941750 // Detect collisions between string and numeric variables when the latter
15951751 // is created later than the former.
1596 if (DefinedVariableTable.find(CmdlineName) !=
1597 DefinedVariableTable.end()) {
1752 if (DefinedVariableTable.find(VarName) != DefinedVariableTable.end()) {
15981753 SM.PrintMessage(
1599 SMLoc::getFromPointer(CmdlineName.data()), SourceMgr::DK_Error,
1600 "string variable with name '" + CmdlineName + "' already exists");
1754 SMLoc::getFromPointer(VarName.data()), SourceMgr::DK_Error,
1755 "string variable with name '" + VarName + "' already exists");
16011756 ErrorFound = true;
16021757 continue;
16031758 }
16121767 ErrorFound = true;
16131768 continue;
16141769 }
1615 auto DefinedNumericVariable = makeNumericVariable(CmdlineName, Val);
1770 auto DefinedNumericVariable = makeNumericVariable(0, VarName);
1771 DefinedNumericVariable->setValue(Val);
16161772
16171773 // Record this variable definition.
1618 GlobalNumericVariableTable[CmdlineName] = DefinedNumericVariable;
1774 GlobalNumericVariableTable[DefinedNumericVariable->getName()] =
1775 DefinedNumericVariable;
16191776 } else {
16201777 // String variable definition.
16211778 std::pair CmdlineNameVal = CmdlineDef.split('=');
1622 StringRef Name = CmdlineNameVal.first;
1779 StringRef CmdlineName = CmdlineNameVal.first;
1780 StringRef OrigCmdlineName = CmdlineName;
1781 StringRef Name;
16231782 bool IsPseudo;
1624 unsigned TrailIdx;
1625 if (FileCheckPattern::parseVariable(Name, IsPseudo, TrailIdx) ||
1626 IsPseudo || TrailIdx != Name.size() || Name.empty()) {
1627 SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
1628 "invalid name in string variable definition '" + Name +
1629 "'");
1783 if (FileCheckPattern::parseVariable(CmdlineName, Name, IsPseudo) ||
1784 IsPseudo || !CmdlineName.empty()) {
1785 SM.PrintMessage(SMLoc::getFromPointer(OrigCmdlineName.data()),
1786 SourceMgr::DK_Error,
1787 "invalid name in string variable definition '" +
1788 OrigCmdlineName + "'");
16301789 ErrorFound = true;
16311790 continue;
16321791 }
16451804 // Mark the string variable as defined to detect collisions between
16461805 // string and numeric variables in DefineCmdlineVariables when the latter
16471806 // is created later than the former. We cannot reuse GlobalVariableTable
1648 // for that by populating it with an empty string since we would then
1807 // for this by populating it with an empty string since we would then
16491808 // lose the ability to detect the use of an undefined variable in
16501809 // match().
16511810 DefinedVariableTable[Name] = true;
33 RUN: not FileCheck -D#10VALUE=10 --input-file %s %s 2>&1 \
44 RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIFMT
55
6 NUMERRCLIFMT: Global defines:1:20: error: invalid name in numeric variable definition '10VALUE'
6 NUMERRCLIFMT: Global defines:1:20: error: invalid variable name
77 NUMERRCLIFMT-NEXT: Global define #1: #10VALUE=10
88 NUMERRCLIFMT-NEXT: {{^ \^$}}
99
1111 RUN: not FileCheck -D#@VALUE=10 --input-file %s %s 2>&1 \
1212 RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLIPSEUDO
1313
14 NUMERRCLIPSEUDO: Global defines:1:20: error: invalid name in numeric variable definition '@VALUE'
14 NUMERRCLIPSEUDO: Global defines:1:20: error: definition of pseudo numeric variable unsupported
1515 NUMERRCLIPSEUDO-NEXT: Global define #1: #@VALUE=10
1616 NUMERRCLIPSEUDO-NEXT: {{^ \^$}}
1717
1919 RUN: not FileCheck -D#VALUE+2=10 --input-file %s %s 2>&1 \
2020 RUN: | FileCheck %s --strict-whitespace --check-prefix NUMERRCLITRAIL
2121
22 NUMERRCLITRAIL: Global defines:1:20: error: invalid name in numeric variable definition 'VALUE+2'
22 NUMERRCLITRAIL: Global defines:1:20: error: invalid variable name
2323 NUMERRCLITRAIL-NEXT: Global define #1: #VALUE+2=10
2424 NUMERRCLITRAIL-NEXT: {{^ \^$}}
2525
None RUN: FileCheck -D#VAR1=11 --input-file %s %s
0 RUN: FileCheck --input-file %s %s
11
22 ; We use CHECK-NEXT directives to force a match on all lines with digits.
33
4 ; Numeric expressions using variables defined on the command-line without
5 ; spaces
4 ; Numeric variable definition without spaces.
5 DEF NO SPC
6 11
7 CHECK-LABEL: DEF NO SPC
8 CHECK-NEXT: [[#VAR1:]]
9
10 ; Numeric variable definition with different spacing.
11 DEF SPC
12 11
13 11
14 11
15 CHECK-LABEL: DEF SPC
16 CHECK-NEXT: [[# VAR1a:]]
17 CHECK-NEXT: [[# VAR1b :]]
18 CHECK-NEXT: [[# VAR1c : ]]
19
20 ; Numeric expressions using variables defined on other lines without spaces.
621 USE NO SPC
722 11
823 12
924 10
10 CHECK-LABEL: USE NO SPC
25 11
26 11
27 11
28 CHECK-LABEL: USE
1129 CHECK-NEXT: [[#VAR1]]
1230 CHECK-NEXT: [[#VAR1+1]]
1331 CHECK-NEXT: [[#VAR1-1]]
32 CHECK-NEXT: [[#VAR1a]]
33 CHECK-NEXT: [[#VAR1b]]
34 CHECK-NEXT: [[#VAR1c]]
1435
15 ; Numeric expressions using variables defined on the command-line in alternate
16 ; spacing
17 USE ALT SPC
36 ; Numeric expressions using variables defined on other lines with different
37 ; spacing.
38 USE SPC
1839 11
1940 11
2041 12
2546 10
2647 10
2748 10
28 CHECK-LABEL: USE ALT SPC
49 CHECK-LABEL: USE SPC
2950 CHECK-NEXT: [[# VAR1]]
3051 CHECK-NEXT: [[# VAR1 ]]
3152 CHECK-NEXT: [[# VAR1+1]]
3859 CHECK-NEXT: [[# VAR1 - 1 ]]
3960
4061 ; Numeric expressions using variables defined on the command-line and an
41 ; immediate interpreted as an unsigned value
62 ; immediate interpreted as an unsigned value.
4263 ; Note: 9223372036854775819 = 0x8000000000000000 + 11
4364 ; 9223372036854775808 = 0x8000000000000000
4465 USE UNSIGNED IMM
4667 CHECK-LABEL: USE UNSIGNED IMM
4768 CHECK-NEXT: [[#VAR1+9223372036854775808]]
4869
49 ; Numeric expression using undefined variable
70 ; Numeric expression using undefined variable.
5071 RUN: not FileCheck --check-prefix UNDEF-USE --input-file %s %s 2>&1 \
5172 RUN: | FileCheck --strict-whitespace --check-prefix UNDEF-USE-MSG %s
5273
5879 UNDEF-USE-MSG-NEXT: {{U}}NDEF-USE-NEXT: UNDEFVAR: {{\[\[#UNDEFVAR\]\]}}
5980 UNDEF-USE-MSG-NEXT: {{^ \^$}}
6081
61 ; Numeric expression with unsupported operator
62 RUN: not FileCheck -D#VAR1=11 --check-prefixes CHECK,INVAL-OP --input-file %s %s 2>&1 \
82 ; Numeric expression with unsupported operator.
83 RUN: not FileCheck -D#NUMVAR=10 --check-prefix INVAL-OP --input-file %s %s 2>&1 \
6384 RUN: | FileCheck --strict-whitespace --check-prefix INVAL-OP-MSG %s
6485
6586 INVALID OPERATOR
66 VAR1*2: 22
87 NUMVAR*2: 22
6788 INVAL-OP-LABEL: INVALID OPERATOR
68 INVAL-OP-NEXT: VAR1*2: [[#VAR1*2]]
69 INVAL-OP-MSG: numeric-expression.txt:[[#@LINE-1]]:31: error: unsupported numeric operation '*'
70 INVAL-OP-MSG-NEXT: {{I}}NVAL-OP-NEXT: VAR1*2: {{\[\[#VAR1\*2\]\]}}
71 INVAL-OP-MSG-NEXT: {{^ \^$}}
89 INVAL-OP-NEXT: NUMVAR*2: [[#NUMVAR*2]]
90 INVAL-OP-MSG: numeric-expression.txt:[[#@LINE-1]]:35: error: unsupported numeric operation '*'
91 INVAL-OP-MSG-NEXT: {{I}}NVAL-OP-NEXT: NUMVAR*2: {{\[\[#NUMVAR\*2\]\]}}
92 INVAL-OP-MSG-NEXT: {{^ \^$}}
7293
7394 ; Name conflict between Numeric variable definition and string variable
74 ; definition
75 RUN: not FileCheck -D#VAR1=11 -D#NUMVAR=42 --check-prefixes CONFLICT,CONFLICT1 --input-file %s %s 2>&1 \
76 RUN: | FileCheck --strict-whitespace --check-prefix CLI-INPUT-PAT-CONFLICT %s
77 RUN: not FileCheck -D#VAR1=11 -D#NUMVAR=42 -DNUMVAR=foobar --check-prefix CONFLICT --input-file %s %s 2>&1 \
78 RUN: | FileCheck --strict-whitespace --check-prefix CLI-CLI-PAT-CONFLICT %s
79 RUN: not FileCheck -D#VAR1=11 -DPATVAR=foobar -D#PATVAR=42 --check-prefix CONFLICT --input-file %s %s 2>&1 \
80 RUN: | FileCheck --strict-whitespace --check-prefix CLI-CLI-NUM-CONFLICT %s
95 ; definition whether from the command-line or input text.
96 RUN: not FileCheck --check-prefixes CONFLICT,CONFLICT1,CONFLICT2 --input-file %s %s 2>&1 \
97 RUN: | FileCheck --strict-whitespace --check-prefix INPUT-STR-CONFLICT %s
98 RUN: not FileCheck -D#NUMVAR=42 --check-prefixes CONFLICT,CONFLICT2 --input-file %s %s 2>&1 \
99 RUN: | FileCheck --strict-whitespace --check-prefix INPUT-STR-CONFLICT %s
100 RUN: not FileCheck -D#NUMVAR=42 -DNUMVAR=foobar --check-prefix CONFLICT --input-file %s %s 2>&1 \
101 RUN: | FileCheck --strict-whitespace --check-prefix CLI-STR-CONFLICT %s
102 RUN: not FileCheck --check-prefixes CONFLICT,CONFLICT3,CONFLICT4 --input-file %s %s 2>&1 \
103 RUN: | FileCheck --strict-whitespace --check-prefix INPUT-NUM-CONFLICT %s
104 RUN: not FileCheck -DSTRVAR=foobar --check-prefixes CONFLICT,CONFLICT4 --input-file %s %s 2>&1 \
105 RUN: | FileCheck --strict-whitespace --check-prefix INPUT-NUM-CONFLICT %s
106 RUN: not FileCheck -DSTRVAR=foobar -D#STRVAR=42 --check-prefix CONFLICT --input-file %s %s 2>&1 \
107 RUN: | FileCheck --strict-whitespace --check-prefix CLI-NUM-CONFLICT %s
81108
82 PATVAR NUMVAR CONFLICT
109 STRVAR NUMVAR CONFLICT
110 redef1 42
83111 foobar
84 CONFLICT-LABEL: PATVAR NUMVAR CONFLICT
85 CONFLICT1-NEXT: [[NUMVAR:foo.*]]
86 CLI-INPUT-PAT-CONFLICT: numeric-expression.txt:[[#@LINE-1]]:19: error: numeric variable with name 'NUMVAR' already exists
87 CLI-INPUT-PAT-CONFLICT-NEXT: {{C}}ONFLICT1-NEXT: {{\[\[NUMVAR:foo\.\*\]\]}}
88 CLI-INPUT-PAT-CONFLICT-NEXT: {{^ \^$}}
89 CLI-CLI-PAT-CONFLICT: Global defines:3:19: error: numeric variable with name 'NUMVAR' already exists
90 CLI-CLI-PAT-CONFLICT-NEXT: Global define #3: NUMVAR=foobar
91 CLI-CLI-PAT-CONFLICT-NEXT: {{^ \^$}}
92 CLI-CLI-NUM-CONFLICT: Global defines:3:20: error: string variable with name 'PATVAR' already exists
93 CLI-CLI-NUM-CONFLICT-NEXT: Global define #3: #PATVAR=42
94 CLI-CLI-NUM-CONFLICT-NEXT: {{^ \^$}}
112 redef2 42
113 CONFLICT-LABEL: STRVAR NUMVAR CONFLICT
114 CONFLICT1-NEXT: redef1 [[#NUMVAR:]]
115 CONFLICT2: [[NUMVAR:foo.*]]
116 CONFLICT3: [[STRVAR:foo.*]]
117 CONFLICT4: redef2 [[#STRVAR:]]
118 INPUT-STR-CONFLICT: numeric-expression.txt:[[#@LINE-3]]:14: error: numeric variable with name 'NUMVAR' already exists
119 INPUT-STR-CONFLICT-NEXT: {{C}}ONFLICT2: {{\[\[NUMVAR:foo\.\*\]\]}}
120 INPUT-STR-CONFLICT-NEXT: {{^ \^$}}
121 CLI-STR-CONFLICT: Global defines:2:19: error: numeric variable with name 'NUMVAR' already exists
122 CLI-STR-CONFLICT-NEXT: Global define #2: NUMVAR=foobar
123 CLI-STR-CONFLICT-NEXT: {{^ \^$}}
124 INPUT-NUM-CONFLICT: numeric-expression.txt:[[#@LINE-7]]:22: error: string variable with name 'STRVAR' already exists
125 INPUT-NUM-CONFLICT-NEXT: CONFLICT4: redef2 {{\[\[#STRVAR:\]\]}}
126 INPUT-NUM-CONFLICT-NEXT: {{^ \^$}}
127 CLI-NUM-CONFLICT: Global defines:2:20: error: string variable with name 'STRVAR' already exists
128 CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42
129 CLI-NUM-CONFLICT-NEXT: {{^ \^$}}
0 ; Test that variables not starting with dollar sign get undefined after a
11 ; CHECK-LABEL directive iff --enable-var-scope is used.
22
3 RUN: FileCheck -D#LOCNUM=1 -D'#$GLOBNUM=1' --check-prefixes CHECK,LOCAL3,GLOBAL --input-file %s %s
4 RUN: FileCheck -D#LOCNUM=1 -D'#$GLOBNUM=1' --check-prefixes CHECK,GLOBAL --enable-var-scope --input-file %s %s
5 RUN: not FileCheck -D#LOCNUM=1 -D#'$GLOBNUM=1' --check-prefixes CHECK,LOCAL1 --enable-var-scope --input-file %s %s 2>&1 \
3 ; Reference run: variables remain defined at all time when not using
4 ; --enable-var-scope option.
5 RUN: FileCheck --check-prefixes CHECK,LOCAL3,GLOBAL --input-file %s %s
6
7 RUN: FileCheck --check-prefixes CHECK,GLOBAL --enable-var-scope --input-file %s %s
8 RUN: not FileCheck --check-prefixes CHECK,LOCAL1 --enable-var-scope --input-file %s %s 2>&1 \
69 RUN: | FileCheck --check-prefixes ERRUNDEF,ERRUNDEFLOCAL %s
7 RUN: not FileCheck -D#LOCNUM=1 -D#'$GLOBNUM=1' --check-prefixes CHECK,LOCAL2 --enable-var-scope --input-file %s %s 2>&1 \
10 RUN: not FileCheck --check-prefixes CHECK,LOCAL2 --enable-var-scope --input-file %s %s 2>&1 \
811 RUN: | FileCheck --check-prefixes ERRUNDEF,ERRUNDEFLOCNUM %s
9 RUN: not FileCheck -D#LOCNUM=1 -D#'$GLOBNUM=1' --check-prefixes CHECK,LOCAL3 --enable-var-scope --input-file %s %s 2>&1 \
12 RUN: not FileCheck --check-prefixes CHECK,LOCAL3 --enable-var-scope --input-file %s %s 2>&1 \
1013 RUN: | FileCheck --check-prefixes ERRUNDEF,ERRUNDEFLOCAL,ERRUNDEFLOCNUM %s
1114
1215 local1
1316 global1
14 CHECK: [[LOCAL:loc[^[:digit:]]*]][[#LOCNUM]]
15 CHECK: [[$GLOBAL:glo[^[:digit:]]*]][[#$GLOBNUM]]
17 CHECK: [[LOCAL:loc[^[:digit:]]*]][[#LOCNUM:]]
18 CHECK: [[$GLOBAL:glo[^[:digit:]]*]][[#$GLOBNUM:]]
1619
1720 local2
1821 global2
None ; RUN: FileCheck -D#NUMVAR=42 -input-file %s %s 2>&1 | FileCheck -check-prefix QUIET --allow-empty %s
1 ; RUN: FileCheck -v -D#NUMVAR=42 -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix V %s
2 ; RUN: FileCheck -vv -D#NUMVAR=42 -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefixes V,VV %s
0 ; RUN: FileCheck -input-file %s %s 2>&1 | FileCheck -check-prefix QUIET --allow-empty %s
1 ; RUN: FileCheck -v -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefix V %s
2 ; RUN: FileCheck -vv -input-file %s %s 2>&1 | FileCheck --strict-whitespace -check-prefixes V,VV %s
33
44 foo
55 bar
2828 VV-NEXT: {{^}}bar{{$}}
2929 VV-NEXT: {{^}}^{{$}}
3030
31 NUMVAR:42
31 NUMVAR=42
3232 NUMVAR - 1:41
33 CHECK: NUMVAR:[[#NUMVAR]]
33 CHECK: NUMVAR=[[#NUMVAR:]]
3434 CHECK-NOT: [[#NUMVAR + 1]]
3535 CHECK-NEXT: NUMVAR - 1:[[#NUMVAR - 1]]
3636
3737 V: verbose.txt:[[#@LINE-4]]:8: remark: {{C}}HECK: expected string found in input
38 V-NEXT: {{C}}HECK: {{NUMVAR:[[][[]#NUMVAR[]][]]$}}
38 V-NEXT: {{C}}HECK: {{NUMVAR=[[][[]#NUMVAR:[]][]]$}}
3939 V-NEXT: {{^ \^$}}
4040 V-NEXT: verbose.txt:[[#@LINE-9]]:1: note: found here
41 V-NEXT: {{^}}NUMVAR:42{{$}}
42 V-NEXT: {{^}}^~~~~~~~~{{$}}
43 V-NEXT: verbose.txt:[[#@LINE-12]]:1: note: with "NUMVAR" equal to "42"
44 V-NEXT: {{^}}NUMVAR:42{{$}}
41 V-NEXT: {{^}}NUMVAR=42{{$}}
4542 V-NEXT: {{^}}^~~~~~~~~{{$}}
4643
47 V-NEXT: verbose.txt:[[#@LINE-12]]:13: remark: {{C}}HECK-NEXT: expected string found in input
44 V-NEXT: verbose.txt:[[#@LINE-9]]:13: remark: {{C}}HECK-NEXT: expected string found in input
4845 V-NEXT: {{C}}HECK-NEXT: {{NUMVAR - 1:[[][[]#NUMVAR - 1[]][]]$}}
4946 V-NEXT: {{^ \^$}}
50 V-NEXT: verbose.txt:[[#@LINE-18]]:1: note: found here
47 V-NEXT: verbose.txt:[[#@LINE-15]]:1: note: found here
5148 V-NEXT: {{^}}NUMVAR - 1:41{{$}}
5249 V-NEXT: {{^}}^~~~~~~~~~~~~{{$}}
53 V-NEXT: verbose.txt:[[#@LINE-21]]:1: note: with "NUMVAR - 1" equal to "41"
50 V-NEXT: verbose.txt:[[#@LINE-18]]:1: note: with "NUMVAR - 1" equal to "41"
5451 V-NEXT: {{^}}NUMVAR - 1:41{{$}}
5552 V-NEXT: {{^}}^~~~~~~~~~~~~{{$}}
5653
57 VV-NEXT: verbose.txt:[[#@LINE-23]]:12: remark: {{C}}HECK-NOT: excluded string not found in input
54 VV-NEXT: verbose.txt:[[#@LINE-20]]:12: remark: {{C}}HECK-NOT: excluded string not found in input
5855 VV-NEXT: {{C}}HECK-NOT: {{[[][[]#NUMVAR [+] 1[]][]]$}}
59 VV-NEXT: {{^ \^$}}
60 VV-NEXT: verbose.txt:[[#@LINE-28]]:1: note: scanning from here
56 VV-NEXT: {{^ \^$}}
57 VV-NEXT: verbose.txt:[[#@LINE-25]]:1: note: scanning from here
6158 VV-NEXT: {{^}}NUMVAR - 1:41{{$}}
6259 VV-NEXT: {{^}}^{{$}}
6360
1414 class FileCheckTest : public ::testing::Test {};
1515
1616 TEST_F(FileCheckTest, NumericVariable) {
17 FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
17 // Undefined variable: getValue and clearValue fails, setValue works.
18 FileCheckNumericVariable FooVar = FileCheckNumericVariable(1, "FOO");
1819 EXPECT_EQ("FOO", FooVar.getName());
19
20 // Defined variable: getValue returns a value, setValue fails and value
21 // remains unchanged.
2220 llvm::Optional Value = FooVar.getValue();
21 EXPECT_FALSE(Value);
22 EXPECT_TRUE(FooVar.clearValue());
23 EXPECT_FALSE(FooVar.setValue(42));
24
25 // Defined variable: getValue returns value set, setValue fails.
26 Value = FooVar.getValue();
2327 EXPECT_TRUE(Value);
2428 EXPECT_EQ(42U, *Value);
2529 EXPECT_TRUE(FooVar.setValue(43));
3236 Value = FooVar.getValue();
3337 EXPECT_FALSE(Value);
3438 EXPECT_TRUE(FooVar.clearValue());
35
36 // Undefined variable: setValue works, getValue returns value set.
37 EXPECT_FALSE(FooVar.setValue(43));
38 Value = FooVar.getValue();
39 EXPECT_TRUE(Value);
40 EXPECT_EQ(43U, *Value);
4139 }
4240
4341 uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
7775 }
7876
7977 TEST_F(FileCheckTest, ParseVar) {
80 StringRef VarName = "GoodVar42";
78 StringRef OrigVarName = "GoodVar42";
79 StringRef VarName = OrigVarName;
80 StringRef ParsedName;
8181 bool IsPseudo = true;
82 unsigned TrailIdx = 0;
83 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
84 EXPECT_FALSE(IsPseudo);
85 EXPECT_EQ(TrailIdx, VarName.size());
86
87 VarName = "$GoodGlobalVar";
88 IsPseudo = true;
89 TrailIdx = 0;
90 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
91 EXPECT_FALSE(IsPseudo);
92 EXPECT_EQ(TrailIdx, VarName.size());
93
94 VarName = "@GoodPseudoVar";
95 IsPseudo = true;
96 TrailIdx = 0;
97 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
82 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
83 EXPECT_EQ(ParsedName, OrigVarName);
84 EXPECT_TRUE(VarName.empty());
85 EXPECT_FALSE(IsPseudo);
86
87 VarName = OrigVarName = "$GoodGlobalVar";
88 IsPseudo = true;
89 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
90 EXPECT_EQ(ParsedName, OrigVarName);
91 EXPECT_TRUE(VarName.empty());
92 EXPECT_FALSE(IsPseudo);
93
94 VarName = OrigVarName = "@GoodPseudoVar";
95 IsPseudo = true;
96 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
97 EXPECT_EQ(ParsedName, OrigVarName);
98 EXPECT_TRUE(VarName.empty());
9899 EXPECT_TRUE(IsPseudo);
99 EXPECT_EQ(TrailIdx, VarName.size());
100100
101101 VarName = "42BadVar";
102 EXPECT_TRUE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
102 EXPECT_TRUE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
103103
104104 VarName = "$@";
105 EXPECT_TRUE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
106
107 VarName = "B@dVar";
108 IsPseudo = true;
109 TrailIdx = 0;
110 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
111 EXPECT_FALSE(IsPseudo);
112 EXPECT_EQ(TrailIdx, 1U);
113
114 VarName = "B$dVar";
115 IsPseudo = true;
116 TrailIdx = 0;
117 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
118 EXPECT_FALSE(IsPseudo);
119 EXPECT_EQ(TrailIdx, 1U);
105 EXPECT_TRUE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
106
107 VarName = OrigVarName = "B@dVar";
108 IsPseudo = true;
109 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
110 EXPECT_EQ(VarName, OrigVarName.substr(1));
111 EXPECT_EQ(ParsedName, "B");
112 EXPECT_FALSE(IsPseudo);
113
114 VarName = OrigVarName = "B$dVar";
115 IsPseudo = true;
116 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
117 EXPECT_EQ(VarName, OrigVarName.substr(1));
118 EXPECT_EQ(ParsedName, "B");
119 EXPECT_FALSE(IsPseudo);
120120
121121 VarName = "BadVar+";
122122 IsPseudo = true;
123 TrailIdx = 0;
124 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
125 EXPECT_FALSE(IsPseudo);
126 EXPECT_EQ(TrailIdx, VarName.size() - 1);
123 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
124 EXPECT_EQ(VarName, "+");
125 EXPECT_EQ(ParsedName, "BadVar");
126 EXPECT_FALSE(IsPseudo);
127127
128128 VarName = "BadVar-";
129129 IsPseudo = true;
130 TrailIdx = 0;
131 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
132 EXPECT_FALSE(IsPseudo);
133 EXPECT_EQ(TrailIdx, VarName.size() - 1);
130 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
131 EXPECT_EQ(VarName, "-");
132 EXPECT_EQ(ParsedName, "BadVar");
133 EXPECT_FALSE(IsPseudo);
134134
135135 VarName = "BadVar:";
136136 IsPseudo = true;
137 TrailIdx = 0;
138 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, IsPseudo, TrailIdx));
139 EXPECT_FALSE(IsPseudo);
140 EXPECT_EQ(TrailIdx, VarName.size() - 1);
137 EXPECT_FALSE(FileCheckPattern::parseVariable(VarName, ParsedName, IsPseudo));
138 EXPECT_EQ(VarName, ":");
139 EXPECT_EQ(ParsedName, "BadVar");
140 EXPECT_FALSE(IsPseudo);
141141 }
142142
143143 static StringRef bufferize(SourceMgr &SM, StringRef Str) {
148148 return StrBufferRef;
149149 }
150150
151 class ExprTester {
151 class PatternTester {
152152 private:
153 size_t LineNumber = 1;
153154 SourceMgr SM;
154155 FileCheckRequest Req;
155156 FileCheckPatternContext Context;
156 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
157 FileCheckPattern P =
158 FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
157159
158160 public:
159 ExprTester() {
161 PatternTester() {
160162 std::vector GlobalDefines;
161163 GlobalDefines.emplace_back(std::string("#FOO=42"));
164 GlobalDefines.emplace_back(std::string("BAR=BAZ"));
162165 Context.defineCmdlineVariables(GlobalDefines, SM);
163 // Call ParsePattern to have @LINE defined.
164 P.ParsePattern("N/A", "CHECK", SM, 1, Req);
166 // Call parsePattern to have @LINE defined.
167 P.parsePattern("N/A", "CHECK", SM, Req);
168 // parsePattern does not expect to be called twice for the same line and
169 // will set FixedStr and RegExStr incorrectly if it is. Therefore prepare
170 // a pattern for a different line.
171 initNextPattern();
165172 }
166173
167 bool parseExpect(std::string &VarName, std::string &Trailer) {
168 bool IsPseudo = VarName[0] == '@';
169 std::string NameTrailer = VarName + Trailer;
170 StringRef NameTrailerRef = bufferize(SM, NameTrailer);
171 StringRef VarNameRef = NameTrailerRef.substr(0, VarName.size());
172 StringRef TrailerRef = NameTrailerRef.substr(VarName.size());
173 return P.parseNumericSubstitution(VarNameRef, IsPseudo, TrailerRef, SM) ==
174 nullptr;
174 void initNextPattern() {
175 P = FileCheckPattern(Check::CheckPlain, &Context, LineNumber++);
176 }
177
178 bool parseNumVarDefExpect(StringRef Expr) {
179 StringRef ExprBufferRef = bufferize(SM, Expr);
180 StringRef Name;
181 return FileCheckPattern::parseNumericVariableDefinition(ExprBufferRef, Name,
182 &Context, SM);
183 }
184
185 bool parseSubstExpect(StringRef Expr) {
186 StringRef ExprBufferRef = bufferize(SM, Expr);
187 FileCheckNumericVariable *DefinedNumericVariable;
188 return P.parseNumericSubstitutionBlock(
189 ExprBufferRef, DefinedNumericVariable, SM) == nullptr;
190 }
191
192 bool parsePatternExpect(StringRef Pattern) {
193 StringRef PatBufferRef = bufferize(SM, Pattern);
194 return P.parsePattern(PatBufferRef, "CHECK", SM, Req);
195 }
196
197 bool matchExpect(StringRef Buffer) {
198 StringRef BufferRef = bufferize(SM, Buffer);
199 size_t MatchLen;
200 return P.match(BufferRef, MatchLen, SM);
175201 }
176202 };
177203
204 TEST_F(FileCheckTest, ParseNumericVariableDefinition) {
205 PatternTester Tester;
206
207 // Invalid definition of pseudo.
208 EXPECT_TRUE(Tester.parseNumVarDefExpect("@LINE"));
209
210 // Conflict with pattern variable.
211 EXPECT_TRUE(Tester.parseNumVarDefExpect("BAR"));
212
213 // Defined variable.
214 EXPECT_FALSE(Tester.parseNumVarDefExpect("FOO"));
215 }
216
178217 TEST_F(FileCheckTest, ParseExpr) {
179 ExprTester Tester;
180
181 // @LINE with offset.
182 std::string VarName = "@LINE";
183 std::string Trailer = "+3";
184 EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
185
186 // @LINE only.
187 Trailer = "";
188 EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
189
190 // Defined variable.
191 VarName = "FOO";
192 EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
193
194 // Undefined variable.
195 VarName = "UNDEF";
196 EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
197
198 // Wrong Pseudovar.
199 VarName = "@FOO";
200 EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
218 PatternTester Tester;
219
220 // Variable definition.
221
222 // Definition of invalid variable.
223 EXPECT_TRUE(Tester.parseSubstExpect("10VAR:"));
224 EXPECT_TRUE(Tester.parseSubstExpect("@FOO:"));
225 EXPECT_TRUE(Tester.parseSubstExpect("@LINE:"));
226
227 // Garbage after name of variable being defined.
228 EXPECT_TRUE(Tester.parseSubstExpect("VAR GARBAGE:"));
229
230 // Variable defined to numeric expression.
231 EXPECT_TRUE(Tester.parseSubstExpect("VAR1: FOO"));
232
233 // Acceptable variable definition.
234 EXPECT_FALSE(Tester.parseSubstExpect("VAR1:"));
235 EXPECT_FALSE(Tester.parseSubstExpect(" VAR2:"));
236 EXPECT_FALSE(Tester.parseSubstExpect("VAR3 :"));
237 EXPECT_FALSE(Tester.parseSubstExpect("VAR3: "));
238
239 // Numeric expression.
240
241 // Unacceptable variable.
242 EXPECT_TRUE(Tester.parseSubstExpect("10VAR"));
243 EXPECT_TRUE(Tester.parseSubstExpect("@FOO"));
244 EXPECT_TRUE(Tester.parseSubstExpect("UNDEF"));
245
246 // Only valid variable.
247 EXPECT_FALSE(Tester.parseSubstExpect("@LINE"));
248 EXPECT_FALSE(Tester.parseSubstExpect("FOO"));
249
250 // Use variable defined on same line.
251 EXPECT_FALSE(Tester.parsePatternExpect("[[#LINE1VAR:]]"));
252 EXPECT_TRUE(Tester.parseSubstExpect("LINE1VAR"));
201253
202254 // Unsupported operator.
203 VarName = "@LINE";
204 Trailer = "/2";
205 EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
255 EXPECT_TRUE(Tester.parseSubstExpect("@LINE/2"));
206256
207257 // Missing offset operand.
208 VarName = "@LINE";
209 Trailer = "+";
210 EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
258 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+"));
211259
212260 // Cannot parse offset operand.
213 VarName = "@LINE";
214 Trailer = "+x";
215 EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
261 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+x"));
216262
217263 // Unexpected string at end of numeric expression.
218 VarName = "@LINE";
219 Trailer = "+5x";
220 EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
264 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+5x"));
265
266 // Valid expression.
267 EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5"));
268 EXPECT_FALSE(Tester.parseSubstExpect("FOO+4"));
269 }
270
271 TEST_F(FileCheckTest, ParsePattern) {
272 PatternTester Tester;
273
274 // Space in pattern variable expression.
275 EXPECT_TRUE(Tester.parsePatternExpect("[[ BAR]]"));
276
277 // Invalid variable name.
278 EXPECT_TRUE(Tester.parsePatternExpect("[[42INVALID]]"));
279
280 // Invalid pattern variable definition.
281 EXPECT_TRUE(Tester.parsePatternExpect("[[@PAT:]]"));
282 EXPECT_TRUE(Tester.parsePatternExpect("[[PAT+2:]]"));
283
284 // Collision with numeric variable.
285 EXPECT_TRUE(Tester.parsePatternExpect("[[FOO:]]"));
286
287 // Valid use of pattern variable.
288 EXPECT_FALSE(Tester.parsePatternExpect("[[BAR]]"));
289
290 // Valid pattern variable definition.
291 EXPECT_FALSE(Tester.parsePatternExpect("[[PAT:[0-9]+]]"));
292
293 // Invalid numeric expressions.
294 EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
295 EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
296 EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
297 EXPECT_TRUE(Tester.parsePatternExpect("[[#2+@LINE]]"));
298 EXPECT_TRUE(Tester.parsePatternExpect("[[#YUP:@LINE]]"));
299
300 // Valid numeric expressions and numeric variable definition.
301 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO]]"));
302 EXPECT_FALSE(Tester.parsePatternExpect("[[#@LINE+2]]"));
303 EXPECT_FALSE(Tester.parsePatternExpect("[[#NUMVAR:]]"));
304 }
305
306 TEST_F(FileCheckTest, Match) {
307 PatternTester Tester;
308
309 // Check matching a definition only matches a number.
310 Tester.parsePatternExpect("[[#NUMVAR:]]");
311 EXPECT_TRUE(Tester.matchExpect("FAIL"));
312 EXPECT_FALSE(Tester.matchExpect("18"));
313
314 // Check matching the variable defined matches the correct number only
315 Tester.initNextPattern();
316 Tester.parsePatternExpect("[[#NUMVAR]] [[#NUMVAR+2]]");
317 EXPECT_TRUE(Tester.matchExpect("19 21"));
318 EXPECT_TRUE(Tester.matchExpect("18 21"));
319 EXPECT_FALSE(Tester.matchExpect("18 20"));
221320 }
222321
223322 TEST_F(FileCheckTest, Substitution) {
235334 // Substitutions of defined pseudo and non-pseudo numeric variables return
236335 // the right value.
237336 FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
238 FileCheckNumericVariable NVar = FileCheckNumericVariable("@N", 10);
337 FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 10);
239338 FileCheckNumExpr NumExprLine = FileCheckNumExpr(doAdd, &LineVar, 0);
240339 FileCheckNumExpr NumExprN = FileCheckNumExpr(doAdd, &NVar, 3);
241340 FileCheckNumericSubstitution SubstitutionLine =
256355 EXPECT_FALSE(SubstitutionN.getResult());
257356
258357 // Substitution of a defined string variable returns the right value.
259 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
358 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context, 1);
260359 StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
261360 Value = StringSubstitution.getResult();
262361 EXPECT_TRUE(Value);
358457 StringRef EmptyVarStr = "EmptyVar";
359458 StringRef UnknownVarStr = "UnknownVar";
360459 llvm::Optional LocalVar = Cxt.getPatternVarValue(LocalVarStr);
361 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt);
362 FileCheckNumExpr *NumExpr =
363 P.parseNumericSubstitution(LocalNumVarRef, false /*IsPseudo*/, "", SM);
460 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
461 FileCheckNumericVariable *DefinedNumericVariable;
462 FileCheckNumExpr *NumExpr = P.parseNumericSubstitutionBlock(
463 LocalNumVarRef, DefinedNumericVariable, SM);
364464 llvm::Optional EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
365465 llvm::Optional UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
366466 EXPECT_TRUE(LocalVar);
382482 // variable clearing due to --enable-var-scope happens after numeric
383483 // expressions are linked to the numeric variables they use.
384484 EXPECT_FALSE(NumExpr->eval());
385 P = FileCheckPattern(Check::CheckPlain, &Cxt);
386 NumExpr =
387 P.parseNumericSubstitution(LocalNumVarRef, false /*IsPseudo*/, "", SM);
485 P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
486 NumExpr = P.parseNumericSubstitutionBlock(LocalNumVarRef,
487 DefinedNumericVariable, SM);
388488 EXPECT_FALSE(NumExpr);
389489 EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
390490 EXPECT_FALSE(EmptyVar);
399499 llvm::Optional GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
400500 EXPECT_TRUE(GlobalVar);
401501 EXPECT_EQ(*GlobalVar, "BAR");
402 P = FileCheckPattern(Check::CheckPlain, &Cxt);
403 NumExpr =
404 P.parseNumericSubstitution(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
502 P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
503 NumExpr = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
504 DefinedNumericVariable, SM);
405505 EXPECT_TRUE(NumExpr);
406506 NumExprVal = NumExpr->eval();
407507 EXPECT_TRUE(NumExprVal);
411511 Cxt.clearLocalVars();
412512 GlobalVar = Cxt.getPatternVarValue(GlobalVarStr);
413513 EXPECT_TRUE(GlobalVar);
414 P = FileCheckPattern(Check::CheckPlain, &Cxt);
415 NumExpr =
416 P.parseNumericSubstitution(GlobalNumVarRef, false /*IsPseudo*/, "", SM);
514 P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
515 NumExpr = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
516 DefinedNumericVariable, SM);
417517 EXPECT_TRUE(NumExpr);
418518 NumExprVal = NumExpr->eval();
419519 EXPECT_TRUE(NumExprVal);