[llvm] r347092 - Preprocessing support in tablegen.
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 16 14:14:03 PST 2018
The patch breaks this bot:
http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/26263/steps/check-llvm%20asan/logs/stdio
- Testing: 28663 tests, 64 threads --
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.
FAIL: LLVM :: TableGen/prep-diag12.td (22344 of 28663)
******************** TEST 'LLVM :: TableGen/prep-diag12.td' FAILED
********************
Script:
--
: 'RUN: at line 1'; not
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag12.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag12.td
--
Exit Code: 1
Command Output (stderr):
--
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag12.td:3:11:
error: CHECK: expected string not found in input
// CHECK: error: Reached EOF without matching #endif
^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:23:1: note: possible intended match here
allocated by thread T0 here:
^
--
********************
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.
FAIL: LLVM :: TableGen/prep-diag2.td (22346 of 28663)
******************** TEST 'LLVM :: TableGen/prep-diag2.td' FAILED
********************
Script:
--
: 'RUN: at line 1'; not
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-DDIAG1 -I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag2.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
--check-prefixes=DIAG1
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag2.td
: 'RUN: at line 2'; not
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag2.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
--check-prefixes=DIAG2
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag2.td
--
Exit Code: 1
Command Output (stderr):
--
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag2.td:5:11:
error: DIAG1: expected string not found in input
// DIAG1: error: Only comments are supported after #else
^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:31:8: note: possible intended match here
allocated by thread T0 here:
^
--
********************
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.
FAIL: LLVM :: TableGen/prep-region-processing.td (22347 of 28663)
******************** TEST 'LLVM :: TableGen/prep-region-processing.td'
FAILED ********************
Script:
--
: 'RUN: at line 1';
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-region-processing.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-region-processing.td
--implicit-check-not warning:
--
Exit Code: 1
Command Output (stderr):
--
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-region-processing.td:8:11:
error: CHECK: expected string not found in input
// CHECK: def ifdef_disabled3
^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:25:11: note: possible intended match here
#21 0xbca32f in llvm::TableGenMain(char*, bool
(*)(llvm::raw_ostream&, llvm::RecordKeeper&))
/b/sanitizer-x86_64-linux-fast/build/llvm/lib/TableGen/Main.cpp:100:14
^
--
********************
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.
FAIL: LLVM :: TableGen/prep-diag4.td (22349 of 28663)
******************** TEST 'LLVM :: TableGen/prep-diag4.td' FAILED
********************
Script:
--
: 'RUN: at line 1'; not
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag4.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag4.td
--
Exit Code: 1
Command Output (stderr):
--
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag4.td:3:11:
error: CHECK: expected string not found in input
// CHECK: error: double #else
^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:29:56: note: possible intended match here
#5 0xc384a8 in void
std::__1::vector<llvm::TGLexer::PreprocessorControlDesc,
std::__1::allocator<llvm::TGLexer::PreprocessorControlDesc>
>::__push_back_slow_path<llvm::TGLexer::PreprocessorControlDesc>(llvm::TGLexer::PreprocessorControlDesc&&)
/b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/vector:1613
^
--
********************
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.
FAIL: LLVM :: TableGen/prep-diag3.td (22350 of 28663)
******************** TEST 'LLVM :: TableGen/prep-diag3.td' FAILED
********************
Script:
--
: 'RUN: at line 1'; not
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-DDIAG1 -I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag3.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
--check-prefixes=DIAG1
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag3.td
: 'RUN: at line 2'; not
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag3.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
--check-prefixes=DIAG2
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag3.td
--
Exit Code: 1
Command Output (stderr):
--
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag3.td:5:11:
error: DIAG1: expected string not found in input
// DIAG1: error: Only comments are supported after #endif
^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:31:8: note: possible intended match here
allocated by thread T0 here:
^
--
********************
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.
FAIL: LLVM :: TableGen/prep-diag10.td (22351 of 28663)
******************** TEST 'LLVM :: TableGen/prep-diag10.td' FAILED
********************
Script:
--
: 'RUN: at line 1'; not
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag10.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag10.td
--
Exit Code: 1
Command Output (stderr):
--
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag10.td:3:11:
error: CHECK: expected string not found in input
// CHECK: error: Reached EOF without matching #endif
^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:23:1: note: possible intended match here
allocated by thread T0 here:
^
--
********************
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.
FAIL: LLVM :: TableGen/prep-diag11.td (22352 of 28663)
******************** TEST 'LLVM :: TableGen/prep-diag11.td' FAILED
********************
Script:
--
: 'RUN: at line 1'; not
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/llvm-tblgen
-I /b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag11.td
2>&1 | /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/FileCheck
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag11.td
--
Exit Code: 1
Command Output (stderr):
--
/b/sanitizer-x86_64-linux-fast/build/llvm/test/TableGen/prep-diag11.td:3:11:
error: CHECK: expected string not found in input
// CHECK: error: Reached EOF without matching #endif
^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:23:1: note: possible intended match here
allocated by thread T0 here:
^
--
********************
Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90..
Testing Time: 224.74s
********************
Failing Tests (7):
LLVM :: TableGen/prep-diag10.td
LLVM :: TableGen/prep-diag11.td
LLVM :: TableGen/prep-diag12.td
LLVM :: TableGen/prep-diag2.td
LLVM :: TableGen/prep-diag3.td
LLVM :: TableGen/prep-diag4.td
LLVM :: TableGen/prep-region-processing.td
Expected Passes : 27915
Expected Failures : 148
Unsupported Tests : 593
Unexpected Failures: 7
FAILED: test/CMakeFiles/check-llvm
cd /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/test &&
/usr/bin/python2.7
/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/./bin/llvm-lit
-sv /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/test
ninja: build stopped: subcommand failed.
+ echo @@@STEP_FAILURE@@@
+ echo @@@BUILD_STEP check-clang asan@@@
@@@STEP_FAILURE@@@
--------------------------------------------------------------------------------
started: Fri Nov 16 13:04:39 2018
ended: Fri Nov 16 13:16:22 2018
duration: 11 mins, 42 secs
On Fri, Nov 16, 2018 at 1:00 PM Vyacheslav Zakharin via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
> Author: vzakhari
> Date: Fri Nov 16 12:57:29 2018
> New Revision: 347092
>
> URL: http://llvm.org/viewvc/llvm-project?rev=347092&view=rev
> Log:
> Preprocessing support in tablegen.
>
> Differential Revision: https://reviews.llvm.org/D53840
>
>
> Added:
> llvm/trunk/test/TableGen/prep-diag1.td
> llvm/trunk/test/TableGen/prep-diag10.td
> llvm/trunk/test/TableGen/prep-diag11-include.inc
> llvm/trunk/test/TableGen/prep-diag11.td
> llvm/trunk/test/TableGen/prep-diag12-include.inc
> llvm/trunk/test/TableGen/prep-diag12.td
> llvm/trunk/test/TableGen/prep-diag13.td
> llvm/trunk/test/TableGen/prep-diag14.td
> llvm/trunk/test/TableGen/prep-diag2.td
> llvm/trunk/test/TableGen/prep-diag3.td
> llvm/trunk/test/TableGen/prep-diag4.td
> llvm/trunk/test/TableGen/prep-diag5.td
> llvm/trunk/test/TableGen/prep-diag6.td
> llvm/trunk/test/TableGen/prep-diag7.td
> llvm/trunk/test/TableGen/prep-diag8.td
> llvm/trunk/test/TableGen/prep-diag9.td
> llvm/trunk/test/TableGen/prep-region-include.inc
> llvm/trunk/test/TableGen/prep-region-processing.td
> llvm/trunk/test/TableGen/unterminated-c-comment-include.inc
> llvm/trunk/test/TableGen/unterminated-c-comment.td
> llvm/trunk/test/TableGen/unterminated-code-block-include.inc
> llvm/trunk/test/TableGen/unterminated-code-block.td
> Modified:
> llvm/trunk/docs/TableGen/LangRef.rst
> llvm/trunk/lib/TableGen/Main.cpp
> llvm/trunk/lib/TableGen/TGLexer.cpp
> llvm/trunk/lib/TableGen/TGLexer.h
> llvm/trunk/lib/TableGen/TGParser.h
>
> Modified: llvm/trunk/docs/TableGen/LangRef.rst
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/TableGen/LangRef.rst?rev=347092&r1=347091&r2=347092&view=diff
>
> ==============================================================================
> --- llvm/trunk/docs/TableGen/LangRef.rst (original)
> +++ llvm/trunk/docs/TableGen/LangRef.rst Fri Nov 16 12:57:29 2018
> @@ -33,7 +33,7 @@ Lexical Analysis
> ================
>
> TableGen supports BCPL (``// ...``) and nestable C-style (``/* ... */``)
> -comments.
> +comments. TableGen also provides simple `Preprocessing Support`_.
>
> The following is a listing of the basic punctuation tokens::
>
> @@ -448,3 +448,50 @@ applied at the end of parsing the base c
> BaseMultiClassList: `MultiClassID` ("," `MultiClassID`)*
> MultiClassID: `TokIdentifier`
> MultiClassObject: `Def` | `Defm` | `Let` | `Foreach`
> +
> +Preprocessing Support
> +=====================
> +
> +TableGen's embedded preprocessor is only intended for conditional
> compilation.
> +It supports the following directives:
> +
> +.. productionlist::
> + LineBegin: ^
> + LineEnd: "\n" | "\r" | EOF
> + WhiteSpace: " " | "\t"
> + CStyleComment: "/*" (.* - "*/") "*/"
> + BCPLComment: "//" (.* - `LineEnd`) `LineEnd`
> + WhiteSpaceOrCStyleComment: `WhiteSpace` | `CStyleComment`
> + WhiteSpaceOrAnyComment: `WhiteSpace` | `CStyleComment` | `BCPLComment`
> + MacroName: `ualpha` (`ualpha` | "0"..."9")*
> + PrepDefine: `LineBegin` (`WhiteSpaceOrCStyleComment`)*
> + : "#define" (`WhiteSpace`)+ `MacroName`
> + : (`WhiteSpaceOrAnyComment`)* `LineEnd`
> + PrepIfdef: `LineBegin` (`WhiteSpaceOrCStyleComment`)*
> + : "#ifdef" (`WhiteSpace`)+ `MacroName`
> + : (`WhiteSpaceOrAnyComment`)* `LineEnd`
> + PrepElse: `LineBegin` (`WhiteSpaceOrCStyleComment`)*
> + : "#else" (`WhiteSpaceOrAnyComment`)* `LineEnd`
> + PrepEndif: `LineBegin` (`WhiteSpaceOrCStyleComment`)*
> + : "#endif" (`WhiteSpaceOrAnyComment`)* `LineEnd`
> + PrepRegContentException: `PredIfdef` | `PredElse` | `PredEndif` | EOF
> + PrepRegion: .* - `PrepRegContentException`
> + :| `PrepIfDef`
> + : (`PrepRegion`)*
> + : [`PrepElse`]
> + : (`PrepRegion`)*
> + : `PrepEndif`
> +
> +:token:`PrepRegion` may occur anywhere in a TD file, as long as it matches
> +the grammar specification.
> +
> +:token:`PrepDefine` allows defining a :token:`MacroName` so that any
> following
> +:token:`PrepIfdef` - :token:`PrepElse` preprocessing region part and
> +:token:`PrepIfdef` - :token:`PrepEndif` preprocessing region
> +are enabled for TableGen tokens parsing.
> +
> +A preprocessing region, starting (i.e. having its :token:`PrepIfdef`) in
> a file,
> +must end (i.e. have its :token:`PrepEndif`) in the same file.
> +
> +A :token:`MacroName` may be defined externally by using ``{ -D<NAME> }``
> +option of TableGen.
>
> Modified: llvm/trunk/lib/TableGen/Main.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/Main.cpp?rev=347092&r1=347091&r2=347092&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/TableGen/Main.cpp (original)
> +++ llvm/trunk/lib/TableGen/Main.cpp Fri Nov 16 12:57:29 2018
> @@ -46,6 +46,10 @@ static cl::list<std::string>
> IncludeDirs("I", cl::desc("Directory of include files"),
> cl::value_desc("directory"), cl::Prefix);
>
> +static cl::list<std::string>
> +MacroNames("D", cl::desc("Name of the macro to be defined"),
> + cl::value_desc("macro name"), cl::Prefix);
> +
> static int reportError(const char *ProgName, Twine Msg) {
> errs() << ProgName << ": " << Msg;
> errs().flush();
> @@ -91,7 +95,7 @@ int llvm::TableGenMain(char *argv0, Tabl
> // it later.
> SrcMgr.setIncludeDirs(IncludeDirs);
>
> - TGParser Parser(SrcMgr, Records);
> + TGParser Parser(SrcMgr, MacroNames, Records);
>
> if (Parser.ParseFile())
> return 1;
>
> Modified: llvm/trunk/lib/TableGen/TGLexer.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGLexer.cpp?rev=347092&r1=347091&r2=347092&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/TableGen/TGLexer.cpp (original)
> +++ llvm/trunk/lib/TableGen/TGLexer.cpp Fri Nov 16 12:57:29 2018
> @@ -19,6 +19,7 @@
> #include "llvm/Support/MemoryBuffer.h"
> #include "llvm/Support/SourceMgr.h"
> #include "llvm/TableGen/Error.h"
> +#include <algorithm>
> #include <cctype>
> #include <cerrno>
> #include <cstdint>
> @@ -28,11 +29,35 @@
>
> using namespace llvm;
>
> -TGLexer::TGLexer(SourceMgr &SM) : SrcMgr(SM) {
> +namespace {
> +// A list of supported preprocessing directives with their
> +// internal token kinds and names.
> +struct {
> + tgtok::TokKind Kind;
> + const char *Word;
> +} PreprocessorDirs[] = {
> + { tgtok::Ifdef, "ifdef" },
> + { tgtok::Else, "else" },
> + { tgtok::Endif, "endif" },
> + { tgtok::Define, "define" }
> +};
> +} // end anonymous namespace
> +
> +TGLexer::TGLexer(SourceMgr &SM, ArrayRef<std::string> Macros) :
> SrcMgr(SM) {
> CurBuffer = SrcMgr.getMainFileID();
> CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer();
> CurPtr = CurBuf.begin();
> TokStart = nullptr;
> +
> + // Pretend that we enter the "top-level" include file.
> + PrepIncludeStack.push_back(
> + make_unique<std::vector<PreprocessorControlDesc>>());
> +
> + // Put all macros defined in the command line into the DefinedMacros
> set.
> + std::for_each(Macros.begin(), Macros.end(),
> + [this](const std::string &MacroName) {
> + DefinedMacros.insert(MacroName);
> + });
> }
>
> SMLoc TGLexer::getLoc() const {
> @@ -41,11 +66,42 @@ SMLoc TGLexer::getLoc() const {
>
> /// ReturnError - Set the error to the specified string at the specified
> /// location. This is defined to always return tgtok::Error.
> -tgtok::TokKind TGLexer::ReturnError(const char *Loc, const Twine &Msg) {
> +tgtok::TokKind TGLexer::ReturnError(SMLoc Loc, const Twine &Msg) {
> PrintError(Loc, Msg);
> return tgtok::Error;
> }
>
> +tgtok::TokKind TGLexer::ReturnError(const char *Loc, const Twine &Msg) {
> + return ReturnError(SMLoc::getFromPointer(Loc), Msg);
> +}
> +
> +bool TGLexer::processEOF() {
> + SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
> + if (ParentIncludeLoc != SMLoc()) {
> + // If prepExitInclude() detects a problem with the preprocessing
> + // control stack, it will return false. Pretend that we reached
> + // the final EOF and stop lexing more tokens by returning false
> + // to LexToken().
> + if (!prepExitInclude(false))
> + return false;
> +
> + CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc);
> + CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer();
> + CurPtr = ParentIncludeLoc.getPointer();
> + // Make sure TokStart points into the parent file's buffer.
> + // LexToken() assigns to it before calling getNextChar(),
> + // so it is pointing into the included file now.
> + TokStart = CurPtr;
> + return true;
> + }
> +
> + // Pretend that we exit the "top-level" include file.
> + // Note that in case of an error (e.g. control stack imbalance)
> + // the routine will issue a fatal error.
> + prepExitInclude(true);
> + return false;
> +}
> +
> int TGLexer::getNextChar() {
> char CurChar = *CurPtr++;
> switch (CurChar) {
> @@ -57,16 +113,6 @@ int TGLexer::getNextChar() {
> if (CurPtr-1 != CurBuf.end())
> return 0; // Just whitespace.
>
> - // If this is the end of an included file, pop the parent file off the
> - // include stack.
> - SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
> - if (ParentIncludeLoc != SMLoc()) {
> - CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc);
> - CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer();
> - CurPtr = ParentIncludeLoc.getPointer();
> - return getNextChar();
> - }
> -
> // Otherwise, return end of file.
> --CurPtr; // Another call to lex will return EOF again.
> return EOF;
> @@ -83,11 +129,11 @@ int TGLexer::getNextChar() {
> }
> }
>
> -int TGLexer::peekNextChar(int Index) {
> +int TGLexer::peekNextChar(int Index) const {
> return *(CurPtr + Index);
> }
>
> -tgtok::TokKind TGLexer::LexToken() {
> +tgtok::TokKind TGLexer::LexToken(bool FileOrLineStart) {
> TokStart = CurPtr;
> // This always consumes at least one character.
> int CurChar = getNextChar();
> @@ -100,7 +146,18 @@ tgtok::TokKind TGLexer::LexToken() {
>
> // Unknown character, emit an error.
> return ReturnError(TokStart, "Unexpected character");
> - case EOF: return tgtok::Eof;
> + case EOF:
> + // Lex next token, if we just left an include file.
> + // Note that leaving an include file means that the next
> + // symbol is located at the end of 'include "..."'
> + // construct, so LexToken() is called with default
> + // false parameter.
> + if (processEOF())
> + return LexToken();
> +
> + // Return EOF denoting the end of lexing.
> + return tgtok::Eof;
> +
> case ':': return tgtok::colon;
> case ';': return tgtok::semi;
> case '.': return tgtok::period;
> @@ -114,15 +171,27 @@ tgtok::TokKind TGLexer::LexToken() {
> case ')': return tgtok::r_paren;
> case '=': return tgtok::equal;
> case '?': return tgtok::question;
> - case '#': return tgtok::paste;
> + case '#':
> + if (FileOrLineStart) {
> + tgtok::TokKind Kind = prepIsDirective();
> + if (Kind != tgtok::Error)
> + return lexPreprocessor(Kind);
> + }
> +
> + return tgtok::paste;
> +
> + case '\r':
> + PrintFatalError("getNextChar() must never return '\r'");
> + return tgtok::Error;
>
> case 0:
> case ' ':
> case '\t':
> - case '\n':
> - case '\r':
> // Ignore whitespace.
> - return LexToken();
> + return LexToken(FileOrLineStart);
> + case '\n':
> + // Ignore whitespace, and identify the new line.
> + return LexToken(true);
> case '/':
> // If this is the start of a // comment, skip until the end of the
> line or
> // the end of the buffer.
> @@ -133,7 +202,7 @@ tgtok::TokKind TGLexer::LexToken() {
> return tgtok::Error;
> } else // Otherwise, this is an error.
> return ReturnError(TokStart, "Unexpected character");
> - return LexToken();
> + return LexToken(FileOrLineStart);
> case '-': case '+':
> case '0': case '1': case '2': case '3': case '4': case '5': case '6':
> case '7': case '8': case '9': {
> @@ -249,10 +318,10 @@ tgtok::TokKind TGLexer::LexVarName() {
> }
>
> tgtok::TokKind TGLexer::LexIdentifier() {
> - // The first letter is [a-zA-Z_#].
> + // The first letter is [a-zA-Z_].
> const char *IdentStart = TokStart;
>
> - // Match the rest of the identifier regex: [0-9a-zA-Z_#]*
> + // Match the rest of the identifier regex: [0-9a-zA-Z_]*
> while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_')
> ++CurPtr;
>
> @@ -322,6 +391,9 @@ bool TGLexer::LexInclude() {
> // Save the line number and lex buffer of the includer.
> CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer();
> CurPtr = CurBuf.begin();
> +
> + PrepIncludeStack.push_back(
> + make_unique<std::vector<PreprocessorControlDesc>>());
> return false;
> }
>
> @@ -496,3 +568,444 @@ tgtok::TokKind TGLexer::LexExclaim() {
>
> return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown
> operator");
> }
> +
> +bool TGLexer::prepExitInclude(bool IncludeStackMustBeEmpty) {
> + // Report an error, if preprocessor control stack for the current
> + // file is not empty.
> + if (!PrepIncludeStack.back()->empty()) {
> + prepReportPreprocessorStackError();
> +
> + return false;
> + }
> +
> + // Pop the preprocessing controls from the include stack.
> + if (PrepIncludeStack.empty()) {
> + PrintFatalError("Preprocessor include stack is empty");
> + }
> +
> + PrepIncludeStack.pop_back();
> +
> + if (IncludeStackMustBeEmpty) {
> + if (!PrepIncludeStack.empty())
> + PrintFatalError("Preprocessor include stack is not empty");
> + } else {
> + if (PrepIncludeStack.empty())
> + PrintFatalError("Preprocessor include stack is empty");
> + }
> +
> + return true;
> +}
> +
> +tgtok::TokKind TGLexer::prepIsDirective() const {
> + for (unsigned ID = 0; ID < llvm::array_lengthof(PreprocessorDirs);
> ++ID) {
> + int NextChar = *CurPtr;
> + bool Match = true;
> + unsigned I = 0;
> + for (; I < strlen(PreprocessorDirs[ID].Word); ++I) {
> + if (NextChar != PreprocessorDirs[ID].Word[I]) {
> + Match = false;
> + break;
> + }
> +
> + NextChar = peekNextChar(I + 1);
> + }
> +
> + // Check for whitespace after the directive. If there is no
> whitespace,
> + // then we do not recognize it as a preprocessing directive.
> + if (Match) {
> + tgtok::TokKind Kind = PreprocessorDirs[ID].Kind;
> +
> + // New line and EOF may follow only #else/#endif. It will be
> reported
> + // as an error for #ifdef/#define after the call to
> prepLexMacroName().
> + if (NextChar == ' ' || NextChar == '\t' || NextChar == EOF ||
> + NextChar == '\n' ||
> + // It looks like TableGen does not support '\r' as the actual
> + // carriage return, e.g. getNextChar() treats a single '\r'
> + // as '\n'. So we do the same here.
> + NextChar == '\r')
> + return Kind;
> +
> + // Allow comments after some directives, e.g.:
> + // #else// OR #else/**/
> + // #endif// OR #endif/**/
> + //
> + // Note that we do allow comments after #ifdef/#define here, e.g.
> + // #ifdef/**/ AND #ifdef//
> + // #define/**/ AND #define//
> + //
> + // These cases will be reported as incorrect after calling
> + // prepLexMacroName(). We could have supported C-style comments
> + // after #ifdef/#define, but this would complicate the code
> + // for little benefit.
> + if (NextChar == '/') {
> + NextChar = peekNextChar(I + 1);
> +
> + if (NextChar == '*' || NextChar == '/')
> + return Kind;
> +
> + // Pretend that we do not recognize the directive.
> + }
> + }
> + }
> +
> + return tgtok::Error;
> +}
> +
> +bool TGLexer::prepEatPreprocessorDirective(tgtok::TokKind Kind) {
> + TokStart = CurPtr;
> +
> + for (unsigned ID = 0; ID < llvm::array_lengthof(PreprocessorDirs); ++ID)
> + if (PreprocessorDirs[ID].Kind == Kind) {
> + // Advance CurPtr to the end of the preprocessing word.
> + CurPtr += strlen(PreprocessorDirs[ID].Word);
> + return true;
> + }
> +
> + PrintFatalError("Unsupported preprocessing token in "
> + "prepEatPreprocessorDirective()");
> + return false;
> +}
> +
> +tgtok::TokKind TGLexer::lexPreprocessor(
> + tgtok::TokKind Kind, bool ReturnNextLiveToken) {
> +
> + // We must be looking at a preprocessing directive. Eat it!
> + if (!prepEatPreprocessorDirective(Kind))
> + PrintFatalError("lexPreprocessor() called for unknown "
> + "preprocessor directive");
> +
> + if (Kind == tgtok::Ifdef) {
> + StringRef MacroName = prepLexMacroName();
> + if (MacroName.empty())
> + return ReturnError(TokStart, "Expected macro name after #ifdef");
> +
> + bool MacroIsDefined = DefinedMacros.count(MacroName) != 0;
> +
> + // Regardless of whether we are processing tokens or not,
> + // we put the #ifdef control on stack.
> + PrepIncludeStack.back()->push_back(
> + {Kind, MacroIsDefined, SMLoc::getFromPointer(TokStart)});
> +
> + if (!prepSkipDirectiveEnd())
> + return ReturnError(CurPtr,
> + "Only comments are supported after #ifdef NAME");
> +
> + // If we were not processing tokens before this #ifdef,
> + // then just return back to the lines skipping code.
> + if (!ReturnNextLiveToken)
> + return Kind;
> +
> + // If we were processing tokens before this #ifdef,
> + // and the macro is defined, then just return the next token.
> + if (MacroIsDefined)
> + return LexToken();
> +
> + // We were processing tokens before this #ifdef, and the macro
> + // is not defined, so we have to start skipping the lines.
> + // If the skipping is successful, it will return the token following
> + // either #else or #endif corresponding to this #ifdef.
> + if (prepSkipRegion(ReturnNextLiveToken))
> + return LexToken();
> +
> + return tgtok::Error;
> + } else if (Kind == tgtok::Else) {
> + // Check if this #else is correct before calling
> prepSkipDirectiveEnd(),
> + // which will move CurPtr away from the beginning of #else.
> + if (PrepIncludeStack.back()->empty())
> + return ReturnError(TokStart, "#else without #ifdef");
> +
> + auto &IfdefEntry = PrepIncludeStack.back()->back();
> +
> + if (IfdefEntry.Kind != tgtok::Ifdef) {
> + PrintError(TokStart, "double #else");
> + return ReturnError(IfdefEntry.SrcPos, "Previous #else is here");
> + }
> +
> + // Replace the corresponding #ifdef's control with its negation
> + // on the control stack.
> + PrepIncludeStack.back()->pop_back();
> + PrepIncludeStack.back()->push_back(
> + {Kind, !IfdefEntry.IsDefined, SMLoc::getFromPointer(TokStart)});
> +
> + if (!prepSkipDirectiveEnd())
> + return ReturnError(CurPtr, "Only comments are supported after
> #else");
> +
> + // If we were processing tokens before this #else,
> + // we have to start skipping lines until the matching #endif.
> + if (ReturnNextLiveToken) {
> + if (prepSkipRegion(ReturnNextLiveToken))
> + return LexToken();
> +
> + return tgtok::Error;
> + }
> +
> + // Return to the lines skipping code.
> + return Kind;
> + } else if (Kind == tgtok::Endif) {
> + // Check if this #endif is correct before calling
> prepSkipDirectiveEnd(),
> + // which will move CurPtr away from the beginning of #endif.
> + if (PrepIncludeStack.back()->empty())
> + return ReturnError(TokStart, "#endif without #ifdef");
> +
> + auto &IfdefOrElseEntry = PrepIncludeStack.back()->back();
> +
> + if (IfdefOrElseEntry.Kind != tgtok::Ifdef &&
> + IfdefOrElseEntry.Kind != tgtok::Else) {
> + PrintFatalError("Invalid preprocessor control on the stack");
> + return tgtok::Error;
> + }
> +
> + if (!prepSkipDirectiveEnd())
> + return ReturnError(CurPtr, "Only comments are supported after
> #endif");
> +
> + PrepIncludeStack.back()->pop_back();
> +
> + // If we were processing tokens before this #endif, then
> + // we should continue it.
> + if (ReturnNextLiveToken) {
> + return LexToken();
> + }
> +
> + // Return to the lines skipping code.
> + return Kind;
> + } else if (Kind == tgtok::Define) {
> + StringRef MacroName = prepLexMacroName();
> + if (MacroName.empty())
> + return ReturnError(TokStart, "Expected macro name after #define");
> +
> + if (!DefinedMacros.insert(MacroName).second)
> + PrintWarning(getLoc(),
> + "Duplicate definition of macro: " + Twine(MacroName));
> +
> + if (!prepSkipDirectiveEnd())
> + return ReturnError(CurPtr,
> + "Only comments are supported after #define
> NAME");
> +
> + if (!ReturnNextLiveToken) {
> + PrintFatalError("#define must be ignored during the lines
> skipping");
> + return tgtok::Error;
> + }
> +
> + return LexToken();
> + }
> +
> + PrintFatalError("Preprocessing directive is not supported");
> + return tgtok::Error;
> +}
> +
> +bool TGLexer::prepSkipRegion(bool MustNeverBeFalse) {
> + if (!MustNeverBeFalse)
> + PrintFatalError("Invalid recursion.");
> +
> + do {
> + // Skip all symbols to the line end.
> + prepSkipToLineEnd();
> +
> + // Find the first non-whitespace symbol in the next line(s).
> + if (!prepSkipLineBegin())
> + return false;
> +
> + // If the first non-blank/comment symbol on the line is '#',
> + // it may be a start of preprocessing directive.
> + //
> + // If it is not '#' just go to the next line.
> + if (*CurPtr == '#')
> + ++CurPtr;
> + else
> + continue;
> +
> + tgtok::TokKind Kind = prepIsDirective();
> +
> + // If we did not find a preprocessing directive or it is #define,
> + // then just skip to the next line. We do not have to do anything
> + // for #define in the line-skipping mode.
> + if (Kind == tgtok::Error || Kind == tgtok::Define)
> + continue;
> +
> + tgtok::TokKind ProcessedKind = lexPreprocessor(Kind, false);
> +
> + // If lexPreprocessor() encountered an error during lexing this
> + // preprocessor idiom, then return false to the calling
> lexPreprocessor().
> + // This will force tgtok::Error to be returned to the tokens
> processing.
> + if (ProcessedKind == tgtok::Error)
> + return false;
> +
> + if (Kind != ProcessedKind)
> + PrintFatalError("prepIsDirective() and lexPreprocessor() "
> + "returned different token kinds");
> +
> + // If this preprocessing directive enables tokens processing,
> + // then return to the lexPreprocessor() and get to the next token.
> + // We can move from line-skipping mode to processing tokens only
> + // due to #else or #endif.
> + if (prepIsProcessingEnabled()) {
> + if (Kind != tgtok::Else && Kind != tgtok::Endif) {
> + PrintFatalError("Tokens processing was enabled by an unexpected "
> + "preprocessing directive");
> + return false;
> + }
> +
> + return true;
> + }
> + } while (CurPtr != CurBuf.end());
> +
> + // We have reached the end of the file, but never left the
> lines-skipping
> + // mode. This means there is no matching #endif.
> + prepReportPreprocessorStackError();
> + return false;
> +}
> +
> +StringRef TGLexer::prepLexMacroName() {
> + // Skip whitespaces between the preprocessing directive and the macro
> name.
> + while (*CurPtr == ' ' || *CurPtr == '\t')
> + ++CurPtr;
> +
> + TokStart = CurPtr;
> + // Macro names start with [a-zA-Z_].
> + if (*CurPtr != '_' && !isalpha(*CurPtr))
> + return "";
> +
> + // Match the rest of the identifier regex: [0-9a-zA-Z_]*
> + while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_')
> + ++CurPtr;
> +
> + return StringRef(TokStart, CurPtr - TokStart);
> +}
> +
> +bool TGLexer::prepSkipLineBegin() {
> + while (CurPtr != CurBuf.end()) {
> + switch (*CurPtr) {
> + case ' ':
> + case '\t':
> + case '\n':
> + case '\r':
> + break;
> +
> + case '/': {
> + int NextChar = peekNextChar(1);
> + if (NextChar == '*') {
> + // Skip C-style comment.
> + // Note that we do not care about skipping the C++-style comments.
> + // If the line contains "//", it may not contain any processable
> + // preprocessing directive. Just return CurPtr pointing to
> + // the first '/' in this case. We also do not care about
> + // incorrect symbols after the first '/' - we are in
> lines-skipping
> + // mode, so incorrect code is allowed to some extent.
> +
> + // Set TokStart to the beginning of the comment to enable proper
> + // diagnostic printing in case of error in SkipCComment().
> + TokStart = CurPtr;
> +
> + // CurPtr must point to '*' before call to SkipCComment().
> + ++CurPtr;
> + if (SkipCComment())
> + return false;
> + } else {
> + // CurPtr points to the non-whitespace '/'.
> + return true;
> + }
> +
> + // We must not increment CurPtr after the comment was lexed.
> + continue;
> + }
> +
> + default:
> + return true;
> + }
> +
> + ++CurPtr;
> + }
> +
> + // We have reached the end of the file. Return to the lines skipping
> + // code, and allow it to handle the EOF as needed.
> + return true;
> +}
> +
> +bool TGLexer::prepSkipDirectiveEnd() {
> + while (CurPtr != CurBuf.end()) {
> + switch (*CurPtr) {
> + case ' ':
> + case '\t':
> + break;
> +
> + case '\n':
> + case '\r':
> + return true;
> +
> + case '/': {
> + int NextChar = peekNextChar(1);
> + if (NextChar == '/') {
> + // Skip C++-style comment.
> + // We may just return true now, but let's skip to the line/buffer
> end
> + // to simplify the method specification.
> + ++CurPtr;
> + SkipBCPLComment();
> + } else if (NextChar == '*') {
> + // When we are skipping C-style comment at the end of a
> preprocessing
> + // directive, we can skip several lines. If any meaningful TD
> token
> + // follows the end of the C-style comment on the same line, it
> will
> + // be considered as an invalid usage of TD token.
> + // For example, we want to forbid usages like this one:
> + // #define MACRO class Class {}
> + // But with C-style comments we also disallow the following:
> + // #define MACRO /* This macro is used
> + // to ... */ class Class {}
> + // One can argue that this should be allowed, but it does not seem
> + // to be worth of the complication. Moreover, this matches
> + // the C preprocessor behavior.
> +
> + // Set TokStart to the beginning of the comment to enable proper
> + // diagnostic printer in case of error in SkipCComment().
> + TokStart = CurPtr;
> + ++CurPtr;
> + if (SkipCComment())
> + return false;
> + } else {
> + TokStart = CurPtr;
> + PrintError(CurPtr, "Unexpected character");
> + return false;
> + }
> +
> + // We must not increment CurPtr after the comment was lexed.
> + continue;
> + }
> +
> + default:
> + // Do not allow any non-whitespaces after the directive.
> + TokStart = CurPtr;
> + return false;
> + }
> +
> + ++CurPtr;
> + }
> +
> + return true;
> +}
> +
> +void TGLexer::prepSkipToLineEnd() {
> + while (*CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end())
> + ++CurPtr;
> +}
> +
> +bool TGLexer::prepIsProcessingEnabled() {
> + for (auto I = PrepIncludeStack.back()->rbegin(),
> + E = PrepIncludeStack.back()->rend();
> + I != E; ++I) {
> + if (!I->IsDefined)
> + return false;
> + }
> +
> + return true;
> +}
> +
> +void TGLexer::prepReportPreprocessorStackError() {
> + if (PrepIncludeStack.back()->empty())
> + PrintFatalError("prepReportPreprocessorStackError() called with "
> + "empty control stack");
> +
> + auto &PrepControl = PrepIncludeStack.back()->back();
> + PrintError(CurBuf.end(), "Reached EOF without matching #endif");
> + PrintError(PrepControl.SrcPos, "The latest preprocessor control is
> here");
> +
> + TokStart = CurPtr;
> +}
>
> Modified: llvm/trunk/lib/TableGen/TGLexer.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGLexer.h?rev=347092&r1=347091&r2=347092&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/TableGen/TGLexer.h (original)
> +++ llvm/trunk/lib/TableGen/TGLexer.h Fri Nov 16 12:57:29 2018
> @@ -14,11 +14,14 @@
> #ifndef LLVM_LIB_TABLEGEN_TGLEXER_H
> #define LLVM_LIB_TABLEGEN_TGLEXER_H
>
> +#include "llvm/ADT/ArrayRef.h"
> #include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/StringSet.h"
> #include "llvm/Support/DataTypes.h"
> #include "llvm/Support/SMLoc.h"
> #include <cassert>
> #include <map>
> +#include <memory>
> #include <string>
>
> namespace llvm {
> @@ -59,7 +62,11 @@ namespace tgtok {
> BinaryIntVal,
>
> // String valued tokens.
> - Id, StrVal, VarName, CodeFragment
> + Id, StrVal, VarName, CodeFragment,
> +
> + // Preprocessing tokens for internal usage by the lexer.
> + // They are never returned as a result of Lex().
> + Ifdef, Else, Endif, Define
> };
> }
>
> @@ -87,10 +94,10 @@ private:
> DependenciesMapTy Dependencies;
>
> public:
> - TGLexer(SourceMgr &SrcMgr);
> + TGLexer(SourceMgr &SrcMgr, ArrayRef<std::string> Macros);
>
> tgtok::TokKind Lex() {
> - return CurCode = LexToken();
> + return CurCode = LexToken(CurPtr == CurBuf.begin());
> }
>
> const DependenciesMapTy &getDependencies() const {
> @@ -119,12 +126,13 @@ public:
>
> private:
> /// LexToken - Read the next token and return its code.
> - tgtok::TokKind LexToken();
> + tgtok::TokKind LexToken(bool FileOrLineStart = false);
>
> + tgtok::TokKind ReturnError(SMLoc Loc, const Twine &Msg);
> tgtok::TokKind ReturnError(const char *Loc, const Twine &Msg);
>
> int getNextChar();
> - int peekNextChar(int Index);
> + int peekNextChar(int Index) const;
> void SkipBCPLComment();
> bool SkipCComment();
> tgtok::TokKind LexIdentifier();
> @@ -134,6 +142,231 @@ private:
> tgtok::TokKind LexNumber();
> tgtok::TokKind LexBracket();
> tgtok::TokKind LexExclaim();
> +
> + // Process EOF encountered in LexToken().
> + // If EOF is met in an include file, then the method will update
> + // CurPtr, CurBuf and preprocessing include stack, and return true.
> + // If EOF is met in the top-level file, then the method will
> + // update and check the preprocessing include stack, and return false.
> + bool processEOF();
> +
> + // *** Structures and methods for preprocessing support ***
> +
> + // A set of macro names that are defined either via command line or
> + // by using:
> + // #define NAME
> + StringSet<> DefinedMacros;
> +
> + // Each of #ifdef and #else directives has a descriptor associated
> + // with it.
> + //
> + // An ordered list of preprocessing controls defined by #ifdef/#else
> + // directives that are in effect currently is called preprocessing
> + // control stack. It is represented as a vector of
> PreprocessorControlDesc's.
> + //
> + // The control stack is updated according to the following rules:
> + //
> + // For each #ifdef we add an element to the control stack.
> + // For each #else we replace the top element with a descriptor
> + // with an inverted IsDefined value.
> + // For each #endif we pop the top element from the control stack.
> + //
> + // When CurPtr reaches the current buffer's end, the control stack
> + // must be empty, i.e. #ifdef and the corresponding #endif
> + // must be located in the same file.
> + struct PreprocessorControlDesc {
> + // Either tgtok::Ifdef or tgtok::Else.
> + tgtok::TokKind Kind;
> +
> + // True, if the condition for this directive is true, false -
> otherwise.
> + // Examples:
> + // #ifdef NAME : true, if NAME is defined, false -
> otherwise.
> + // ...
> + // #else : false, if NAME is defined, true -
> otherwise.
> + bool IsDefined;
> +
> + // Pointer into CurBuf to the beginning of the preprocessing directive
> + // word, e.g.:
> + // #ifdef NAME
> + // ^ - SrcPos
> + SMLoc SrcPos;
> + };
> +
> + // We want to disallow code like this:
> + // file1.td:
> + // #define NAME
> + // #ifdef NAME
> + // include "file2.td"
> + // EOF
> + // file2.td:
> + // #endif
> + // EOF
> + //
> + // To do this, we clear the preprocessing control stack on entry
> + // to each of the included file. PrepIncludeStack is used to store
> + // preprocessing control stacks for the current file and all its
> + // parent files. The back() element is the preprocessing control
> + // stack for the current file.
> + std::vector<std::unique_ptr<std::vector<PreprocessorControlDesc>>>
> + PrepIncludeStack;
> +
> + // Validate that the current preprocessing control stack is empty,
> + // since we are about to exit a file, and pop the include stack.
> + //
> + // If IncludeStackMustBeEmpty is true, the include stack must be empty
> + // after the popping, otherwise, the include stack must not be empty
> + // after the popping. Basically, the include stack must be empty
> + // only if we exit the "top-level" file (i.e. finish lexing).
> + //
> + // The method returns false, if the current preprocessing control stack
> + // is not empty (e.g. there is an unterminated #ifdef/#else),
> + // true - otherwise.
> + bool prepExitInclude(bool IncludeStackMustBeEmpty);
> +
> + // Look ahead for a preprocessing directive starting from CurPtr. The
> caller
> + // must only call this method, if *(CurPtr - 1) is '#'. If the method
> matches
> + // a preprocessing directive word followed by a whitespace, then it
> returns
> + // one of the internal token kinds, i.e. Ifdef, Else, Endif, Define.
> + //
> + // CurPtr is not adjusted by this method.
> + tgtok::TokKind prepIsDirective() const;
> +
> + // Given a preprocessing token kind, adjusts CurPtr to the end
> + // of the preprocessing directive word. Returns true, unless
> + // an unsupported token kind is passed in.
> + //
> + // We use look-ahead prepIsDirective() and
> prepEatPreprocessorDirective()
> + // to avoid adjusting CurPtr before we are sure that '#' is followed
> + // by a preprocessing directive. If it is not, then we fall back to
> + // tgtok::paste interpretation of '#'.
> + bool prepEatPreprocessorDirective(tgtok::TokKind Kind);
> +
> + // The main "exit" point from the token parsing to preprocessor.
> + //
> + // The method is called for CurPtr, when prepIsDirective() returns
> + // true. The first parameter matches the result of prepIsDirective(),
> + // denoting the actual preprocessor directive to be processed.
> + //
> + // If the preprocessing directive disables the tokens processing, e.g.:
> + // #ifdef NAME // NAME is undefined
> + // then lexPreprocessor() enters the lines-skipping mode.
> + // In this mode, it does not parse any tokens, because the code under
> + // the #ifdef may not even be a correct tablegen code. The preprocessor
> + // looks for lines containing other preprocessing directives, which
> + // may be prepended with whitespaces and C-style comments. If the line
> + // does not contain a preprocessing directive, it is skipped completely.
> + // Otherwise, the preprocessing directive is processed by recursively
> + // calling lexPreprocessor(). The processing of the encountered
> + // preprocessing directives includes updating preprocessing control
> stack
> + // and adding new macros into DefinedMacros set.
> + //
> + // The second parameter controls whether lexPreprocessor() is called
> from
> + // LexToken() (true) or recursively from lexPreprocessor() (false).
> + //
> + // If ReturnNextLiveToken is true, the method returns the next
> + // LEX token following the current directive or following the end
> + // of the disabled preprocessing region corresponding to this directive.
> + // If ReturnNextLiveToken is false, the method returns the first
> parameter,
> + // unless there were errors encountered in the disabled preprocessing
> + // region - in this case, it returns tgtok::Error.
> + tgtok::TokKind lexPreprocessor(tgtok::TokKind Kind,
> + bool ReturnNextLiveToken = true);
> +
> + // Worker method for lexPreprocessor() to skip lines after some
> + // preprocessing directive up to the buffer end or to the directive
> + // that re-enables token processing. The method returns true
> + // upon processing the next directive that re-enables tokens
> + // processing. False is returned if an error was encountered.
> + //
> + // Note that prepSkipRegion() calls lexPreprocessor() to process
> + // encountered preprocessing directives. In this case, the second
> + // parameter to lexPreprocessor() is set to false. Being passed
> + // false ReturnNextLiveToken, lexPreprocessor() must never call
> + // prepSkipRegion(). We assert this by passing ReturnNextLiveToken
> + // to prepSkipRegion() and checking that it is never set to false.
> + bool prepSkipRegion(bool MustNeverBeFalse);
> +
> + // Lex name of the macro after either #ifdef or #define. We could have
> used
> + // LexIdentifier(), but it has special handling of "include" word, which
> + // could result in awkward diagnostic errors. Consider:
> + // ----
> + // #ifdef include
> + // class ...
> + // ----
> + // LexIdentifier() will engage LexInclude(), which will complain about
> + // missing file with name "class". Instead, prepLexMacroName() will
> treat
> + // "include" as a normal macro name.
> + //
> + // On entry, CurPtr points to the end of a preprocessing directive word.
> + // The method allows for whitespaces between the preprocessing directive
> + // and the macro name. The allowed whitespaces are ' ' and '\t'.
> + //
> + // If the first non-whitespace symbol after the preprocessing directive
> + // is a valid start symbol for an identifier (i.e. [a-zA-Z_]), then
> + // the method updates TokStart to the position of the first
> non-whitespace
> + // symbol, sets CurPtr to the position of the macro name's last symbol,
> + // and returns a string reference to the macro name. Otherwise,
> + // TokStart is set to the first non-whitespace symbol after the
> preprocessing
> + // directive, and the method returns an empty string reference.
> + //
> + // In all cases, TokStart may be used to point to the word following
> + // the preprocessing directive.
> + StringRef prepLexMacroName();
> +
> + // Skip any whitespaces starting from CurPtr. The method is used
> + // only in the lines-skipping mode to find the first non-whitespace
> + // symbol after or at CurPtr. Allowed whitespaces are ' ', '\t', '\n'
> + // and '\r'. The method skips C-style comments as well, because
> + // it is used to find the beginning of the preprocessing directive.
> + // If we do not handle C-style comments the following code would
> + // result in incorrect detection of a preprocessing directive:
> + // /*
> + // #ifdef NAME
> + // */
> + // As long as we skip C-style comments, the following code is correctly
> + // recognized as a preprocessing directive:
> + // /* first line comment
> + // second line comment */ #ifdef NAME
> + //
> + // The method returns true upon reaching the first non-whitespace symbol
> + // or EOF, CurPtr is set to point to this symbol. The method returns
> false,
> + // if an error occured during skipping of a C-style comment.
> + bool prepSkipLineBegin();
> +
> + // Skip any whitespaces or comments after a preprocessing directive.
> + // The method returns true upon reaching either end of the line
> + // or end of the file. If there is a multiline C-style comment
> + // after the preprocessing directive, the method skips
> + // the comment, so the final CurPtr may point to one of the next lines.
> + // The method returns false, if an error occured during skipping
> + // C- or C++-style comment, or a non-whitespace symbol appears
> + // after the preprocessing directive.
> + //
> + // The method maybe called both during lines-skipping and tokens
> + // processing. It actually verifies that only whitespaces or/and
> + // comments follow a preprocessing directive.
> + //
> + // After the execution of this mehod, CurPtr points either to new line
> + // symbol, buffer end or non-whitespace symbol following the
> preprocesing
> + // directive.
> + bool prepSkipDirectiveEnd();
> +
> + // Skip all symbols to the end of the line/file.
> + // The method adjusts CurPtr, so that it points to either new line
> + // symbol in the current line or the buffer end.
> + void prepSkipToLineEnd();
> +
> + // Return true, if the current preprocessor control stack is such that
> + // we should allow lexer to process the next token, false - otherwise.
> + //
> + // In particular, the method returns true, if all the #ifdef/#else
> + // controls on the stack have their IsDefined member set to true.
> + bool prepIsProcessingEnabled();
> +
> + // Report an error, if we reach EOF with non-empty preprocessing control
> + // stack. This means there is no matching #endif for the previous
> + // #ifdef/#else.
> + void prepReportPreprocessorStackError();
> };
>
> } // end namespace llvm
>
> Modified: llvm/trunk/lib/TableGen/TGParser.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/TableGen/TGParser.h?rev=347092&r1=347091&r2=347092&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/TableGen/TGParser.h (original)
> +++ llvm/trunk/lib/TableGen/TGParser.h Fri Nov 16 12:57:29 2018
> @@ -115,8 +115,9 @@ class TGParser {
> };
>
> public:
> - TGParser(SourceMgr &SrcMgr, RecordKeeper &records)
> - : Lex(SrcMgr), CurMultiClass(nullptr), Records(records) {}
> + TGParser(SourceMgr &SrcMgr, ArrayRef<std::string> Macros,
> + RecordKeeper &records)
> + : Lex(SrcMgr, Macros), CurMultiClass(nullptr), Records(records) {}
>
> /// ParseFile - Main entrypoint for parsing a tblgen file. These parser
> /// routines return true on error, or false on success.
>
> Added: llvm/trunk/test/TableGen/prep-diag1.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag1.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag1.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag1.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,26 @@
> +// RUN: not llvm-tblgen -DDIAG1 -I %p %s 2>&1 | FileCheck
> --check-prefixes=DIAG1 %s
> +// RUN: not llvm-tblgen -DDIAG4 -I %p %s 2>&1 | FileCheck
> --check-prefixes=DIAG4 %s
> +// RUN: not llvm-tblgen -DDIAG2 -I %p %s 2>&1 | FileCheck
> --check-prefixes=DIAG2 %s
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck --check-prefixes=DIAG3
> %s
> +
> +#ifdef DIAG1
> +// DIAG1: error: Only comments are supported after #define NAME
> +#define ENABLED1/*
> +*/class C;
> +#endif // DIAG1
> +
> +#ifdef DIAG4
> +// DIAG4: warning: Duplicate definition of macro: ENABLED1
> +#define ENABLED1
> +#define ENABLED1
> +#endif // DIAG4
> +
> +#ifdef DIAG2
> +// DIAG2: error: Only comments are supported after #ifdef NAME
> +
> +// Invalid #ifdef below should be detected even if DIAG2 is not defined.
> +// DIAG3: error: Only comments are supported after #ifdef NAME
> +#ifdef DIAG2/*
> +*/class C;
> +#endif
> +#endif // DIAG2
>
> Added: llvm/trunk/test/TableGen/prep-diag10.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag10.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag10.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag10.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,6 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Reached EOF without matching #endif
> +// CHECK: error: The latest preprocessor control is here
> +#ifdef DISABLED
> +#else
>
> Added: llvm/trunk/test/TableGen/prep-diag11-include.inc
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag11-include.inc?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag11-include.inc (added)
> +++ llvm/trunk/test/TableGen/prep-diag11-include.inc Fri Nov 16 12:57:29
> 2018
> @@ -0,0 +1 @@
> +#ifdef ENABLED
>
> Added: llvm/trunk/test/TableGen/prep-diag11.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag11.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag11.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag11.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,8 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Reached EOF without matching #endif
> +// CHECK: error: The latest preprocessor control is here
> +#ifdef DISABLED
> +#else
> +#define ENABLED
> +include "prep-diag11-include.inc"
>
> Added: llvm/trunk/test/TableGen/prep-diag12-include.inc
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag12-include.inc?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag12-include.inc (added)
> +++ llvm/trunk/test/TableGen/prep-diag12-include.inc Fri Nov 16 12:57:29
> 2018
> @@ -0,0 +1,2 @@
> +#ifdef ENABLED
> +#else
>
> Added: llvm/trunk/test/TableGen/prep-diag12.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag12.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag12.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag12.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,8 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Reached EOF without matching #endif
> +// CHECK: error: The latest preprocessor control is here
> +#ifdef DISABLED
> +#else
> +#define ENABLED
> +include "prep-diag12-include.inc"
>
> Added: llvm/trunk/test/TableGen/prep-diag13.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag13.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag13.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag13.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,9 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Reached EOF without matching #endif
> +// CHECK: error: The latest preprocessor control is here
> +#ifdef DISABLED
> +/*
> +#else
> +#endif
> +*/
>
> Added: llvm/trunk/test/TableGen/prep-diag14.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag14.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag14.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag14.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,6 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Reached EOF without matching #endif
> +// CHECK: error: The latest preprocessor control is here
> +#ifdef DISABLED
> +// #endif
>
> Added: llvm/trunk/test/TableGen/prep-diag2.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag2.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag2.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag2.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,14 @@
> +// RUN: not llvm-tblgen -DDIAG1 -I %p %s 2>&1 | FileCheck
> --check-prefixes=DIAG1 %s
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck --check-prefixes=DIAG2
> %s
> +
> +#ifdef DIAG1
> +// DIAG1: error: Only comments are supported after #else
> +
> +// Invalid #else below should be detected even if DIAG1 is not defined.
> +// DIAG2: error: Only comments are supported after #else
> +#ifdef DIAG2//DIAG2
> +#else/*
> +*/class C;
> +#endif
> +#endif // DIAG1
> +
>
> Added: llvm/trunk/test/TableGen/prep-diag3.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag3.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag3.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag3.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,14 @@
> +// RUN: not llvm-tblgen -DDIAG1 -I %p %s 2>&1 | FileCheck
> --check-prefixes=DIAG1 %s
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck --check-prefixes=DIAG2
> %s
> +
> +#ifdef DIAG1
> +// DIAG1: error: Only comments are supported after #endif
> +
> +// Invalid #else below should be detected even if DIAG1 is not defined.
> +// DIAG2: error: Only comments are supported after #endif
> +#ifdef DIAG2//DIAG2
> +#else/*!DIAG2*/
> +#endif/* !DIAG2
> +*/class C;
> +#endif // DIAG1
> +
>
> Added: llvm/trunk/test/TableGen/prep-diag4.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag4.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag4.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag4.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,8 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: double #else
> +// CHECK: error: Previous #else is here
> +#ifdef DIAG1
> +#else
> +#else
> +#endif
>
> Added: llvm/trunk/test/TableGen/prep-diag5.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag5.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag5.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag5.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,6 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: #else without #ifdef
> +#else
> +#else
> +#endif
>
> Added: llvm/trunk/test/TableGen/prep-diag6.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag6.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag6.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag6.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,7 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Expected macro name after #ifdef
> +#ifdef
> +#else
> +#else
> +#endif
>
> Added: llvm/trunk/test/TableGen/prep-diag7.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag7.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag7.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag7.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,4 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: #endif without #ifdef
> +#endif
>
> Added: llvm/trunk/test/TableGen/prep-diag8.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag8.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag8.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag8.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,5 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Expected macro name after #define
> +#define
> +#endif
>
> Added: llvm/trunk/test/TableGen/prep-diag9.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-diag9.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-diag9.td (added)
> +++ llvm/trunk/test/TableGen/prep-diag9.td Fri Nov 16 12:57:29 2018
> @@ -0,0 +1,5 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Reached EOF without matching #endif
> +// CHECK: error: The latest preprocessor control is here
> +#ifdef DISABLED
>
> Added: llvm/trunk/test/TableGen/prep-region-include.inc
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-region-include.inc?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-region-include.inc (added)
> +++ llvm/trunk/test/TableGen/prep-region-include.inc Fri Nov 16 12:57:29
> 2018
> @@ -0,0 +1,8 @@
> +#ifdef ENABLED4
> +def ifdef_enabled4 : C;
> +#else
> +def ifdef_enabled4_else : C;
> +#endif
> +
> +// EOF immediately after ENABLED5
> +#define ENABLED5
>
> Added: llvm/trunk/test/TableGen/prep-region-processing.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/prep-region-processing.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/prep-region-processing.td (added)
> +++ llvm/trunk/test/TableGen/prep-region-processing.td Fri Nov 16
> 12:57:29 2018
> @@ -0,0 +1,150 @@
> +// RUN: llvm-tblgen -I %p %s 2>&1 | FileCheck %s --implicit-check-not
> warning:
> +
> +class C;
> +
> +// TableGen prints records in alpabetical order.
> +// CHECK-NOT: def ifdef_disabled1
> +// CHECK-NOT: def ifdef_disabled2
> +// CHECK: def ifdef_disabled3
> +// CHECK-NOT: def ifdef_disabled4
> +// CHECK-NOT: def ifdef_disabled5
> +// CHECK: def ifdef_disabled4_else
> +// CHECK-NOT: def ifdef_disabled5_else
> +// CHECK: def ifdef_enabled1
> +// CHECK-NOT: def ifdef_enabled2
> +// CHECK: def ifdef_enabled3
> +// CHECK: def ifdef_enabled4
> +// CHECK-NOT: def ifdef_enabled4_else
> +// CHECK: def ifdef_enabled5
> +// CHECK: def ifdef_enabled6
> +// CHECK-NOT: def ifdef_enabled6_else
> +// CHECK-NOT: def ifdef_disabled6
> +// CHECK-NOT: def ifdef_disabled6_else
> +
> +#define ENABLED1
> +#define ENABLED2
> +
> +#ifdef DISABLED1
> +//
> +def ifdef_disabled1 : C;
> +
> +#define DISABLED2/*This one is disabled,
> + because DISABLED1 is.
> +*/
> +#endif
> +
> +#ifdef ENABLED1
> +def ifdef_enabled1 : C;
> +#endif
> +
> +#ifdef DISABLED2/*
> +*/
> +def ifdef_disabled2 : C;
> +#endif
> +
> +/*
> +#ifdef ENABLED2
> +def ifdef_enabled2 : C;
> +#endif
> +*/
> +
> +//#ifdef DISABLED3
> +def ifdef_disabled3 : C;
> +
> +//#endif
> +
> +/* _DISABLED4 */ /* padding */ #ifdef _DISABLED4
> +def ifdef_disabled4 : C;
> +#else// /*!_DISABLED4
> +def ifdef_disabled4_else : C;
> +
> +#define ENABLED3
> +#endif
> +
> +#ifdef __DISABLED5
> +def ifdef_disabled5 : C;
> +/*
> +
> +*/#else
> +#ifdef ENABLED3
> +def ifdef_enabled3 : C;
> +#else /* //!ENABLED3
> +*/
> +def ifdef_disabled5_else : C;
> +#endif
> +#endif
> +
> +#define ENABLED4
> +include "prep-region-include.inc"//ENABLED5 is defined inside
> +
> +#ifdef ENABLED5
> +def ifdef_enabled5 : C;
> +#endif // ENABLED5
> +
> +#ifdef DISABLED6__
> +// Double inclusion is an error.
> +include "prep-region-include.inc"
> +#else
> +#endif
> +
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +#ifdef DIS
> +def ifdef_disabled6 : C;
> +#endif
> +#endif
> +#endif
> +#endif
> +#else
> +def ifdef_disabled6_else : C;
> +#endif
> +#endif
> +#endif
> +#endif
> +#endif
> +#endif
> +#else
> +#define ENAB//ENAB
> +#endif
> +
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +#ifdef ENAB
> +def ifdef_enabled6 : C;
> +#endif
> +#endif
> +#endif
> +#endif
> +#else
> +def ifdef_enabled6_else : C;
> +#endif
> +#endif
> +#endif
> +#endif
> +#endif
> +#endif
> +#endif
> +
> +#ifdef DISABLED_7
> +include "non-existent-file.inc"
> +#endif
> +
> +#ifdef DISABLED_8
> +\\\\\ invalid TD text /////
> +#endif // DISABLED_8
>
> Added: llvm/trunk/test/TableGen/unterminated-c-comment-include.inc
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/unterminated-c-comment-include.inc?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/unterminated-c-comment-include.inc (added)
> +++ llvm/trunk/test/TableGen/unterminated-c-comment-include.inc Fri Nov 16
> 12:57:29 2018
> @@ -0,0 +1,2 @@
> +/* comment starts here and finished in the parent file.
> + TableGen used to allow such usage.
>
> Added: llvm/trunk/test/TableGen/unterminated-c-comment.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/unterminated-c-comment.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/unterminated-c-comment.td (added)
> +++ llvm/trunk/test/TableGen/unterminated-c-comment.td Fri Nov 16
> 12:57:29 2018
> @@ -0,0 +1,5 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Unterminated comment!
> +
> +include "unterminated-c-comment-include.inc" */
>
> Added: llvm/trunk/test/TableGen/unterminated-code-block-include.inc
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/unterminated-code-block-include.inc?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/unterminated-code-block-include.inc (added)
> +++ llvm/trunk/test/TableGen/unterminated-code-block-include.inc Fri Nov
> 16 12:57:29 2018
> @@ -0,0 +1,8 @@
> +class test<code C> {
> + code Code = C;
> +}
> +
> +// TableGen used to allow code blocks starting in one file
> +// and finishing in the parent one. This test checks
> +// that this is reported as an error from now on.
> +def foo : test<[{ hello world!
>
> Added: llvm/trunk/test/TableGen/unterminated-code-block.td
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/unterminated-code-block.td?rev=347092&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/TableGen/unterminated-code-block.td (added)
> +++ llvm/trunk/test/TableGen/unterminated-code-block.td Fri Nov 16
> 12:57:29 2018
> @@ -0,0 +1,5 @@
> +// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
> +
> +// CHECK: error: Unterminated Code Block
> +
> +include "unterminated-code-block-include.inc" }]>;
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20181116/88815ba7/attachment-0001.html>
More information about the llvm-commits
mailing list