From feb54379427093dca566cbea996e7a57b80d73eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjimihe=E2=80=9D?= Date: Thu, 23 Nov 2023 14:19:58 +0800 Subject: [PATCH] PP: Report an error when a # is not the first thing on a line According to the GLSL spec Each number sign (#) can be preceded in its line only by spaces or horizontal tabs. It may also be followed by spaces and horizontal tabs, preceding the directive. --- Test/baseResults/cppBad.vert.out | 4 ++- Test/baseResults/cppBad4.vert.out | 3 +- .../preprocessor/PpContext.h | 32 +++++++++++++++++-- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Test/baseResults/cppBad.vert.out b/Test/baseResults/cppBad.vert.out index 8ab04bc0..e0a1504a 100644 --- a/Test/baseResults/cppBad.vert.out +++ b/Test/baseResults/cppBad.vert.out @@ -1,5 +1,7 @@ cppBad.vert WARNING: 0:1: '#define' : missing space after macro name +ERROR: 0:1: '#' : (#) can be preceded in its line only by spaces or horizontal tabs +ERROR: 0:2: '#' : (#) can be preceded in its line only by spaces or horizontal tabs ERROR: 0:3: 'preprocessor evaluation' : bad expression ERROR: 0:3: '#if' : unexpected tokens following directive ERROR: 0:6: 'string' : End of line in string @@ -7,7 +9,7 @@ ERROR: 0:6: 'string literal' : required extension not requested: Possible extens GL_EXT_debug_printf GL_EXT_spirv_intrinsics ERROR: 0:6: '' : syntax error, unexpected INT, expecting COMMA or SEMICOLON -ERROR: 5 compilation errors. No code generated. +ERROR: 7 compilation errors. No code generated. Shader version: 100 diff --git a/Test/baseResults/cppBad4.vert.out b/Test/baseResults/cppBad4.vert.out index 693ea8e8..23f149db 100644 --- a/Test/baseResults/cppBad4.vert.out +++ b/Test/baseResults/cppBad4.vert.out @@ -1,7 +1,8 @@ cppBad4.vert +ERROR: 0:2: '#' : (#) can be preceded in its line only by spaces or horizontal tabs ERROR: 0:4: 'macro expansion' : unexpected '#' g ERROR: 0:5: '' : syntax error, unexpected SEMICOLON, expecting LEFT_PAREN -ERROR: 2 compilation errors. No code generated. +ERROR: 3 compilation errors. No code generated. Shader version: 100 diff --git a/glslang/MachineIndependent/preprocessor/PpContext.h b/glslang/MachineIndependent/preprocessor/PpContext.h index 18342bf6..1ec30491 100644 --- a/glslang/MachineIndependent/preprocessor/PpContext.h +++ b/glslang/MachineIndependent/preprocessor/PpContext.h @@ -215,6 +215,7 @@ public: virtual bool peekContinuedPasting(int) { return false; } // true when non-spaced tokens can paste virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define) virtual bool isMacroInput() { return false; } + virtual bool isStringInput() { return false; } // Will be called when we start reading tokens from this instance virtual void notifyActivated() {} @@ -355,7 +356,8 @@ protected: // Scanner data: int previous_token; TParseContextBase& parseContext; - + std::vector lastLineTokens; + std::vector lastLineTokenLocs; // Get the next token from *stack* of input sources, popping input sources // that are out of tokens, down until an input source is found that has a token. // Return EndOfInput when there are no more tokens to be found by doing this. @@ -369,7 +371,31 @@ protected: break; popInput(); } - + if (!inputStack.empty() && inputStack.back()->isStringInput()) { + if (token == '\n') { + bool seenNumSign = false; + for (int i = 0; i < (int)lastLineTokens.size() - 1;) { + int curPos = i; + int curToken = lastLineTokens[i++]; + if (curToken == '#' && lastLineTokens[i] == '#') { + curToken = PpAtomPaste; + i++; + } + if (curToken == '#') { + if (seenNumSign) { + parseContext.ppError(lastLineTokenLocs[curPos], "(#) can be preceded in its line only by spaces or horizontal tabs", "#", ""); + } else { + seenNumSign = true; + } + } + } + lastLineTokens.clear(); + lastLineTokenLocs.clear(); + } else { + lastLineTokens.push_back(token); + lastLineTokenLocs.push_back(ppToken->loc); + } + } return token; } int getChar() { return inputStack.back()->getch(); } @@ -522,7 +548,7 @@ protected: public: tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { } virtual int scan(TPpToken*) override; - + bool isStringInput() override { return true; } // Scanner used to get source stream characters. // - Escaped newlines are handled here, invisibly to the caller. // - All forms of newline are handled, and turned into just a '\n'.