From aae1ad82964bb808910024b531fa5c8cc0c7d569 Mon Sep 17 00:00:00 2001 From: Andrew Woloszyn Date: Wed, 24 Jun 2015 17:00:46 -0400 Subject: [PATCH] Added error output to the preprocessor. This patch distinguishes preprocessing errors with normal parsing errors and gives glslangValidator the ability to output preprocessing errors. --- StandAlone/StandAlone.cpp | 40 +++++-- .../preprocessor.edge_cases.vert.err | 2 + Test/baseResults/preprocessor.errors.vert.err | 8 ++ Test/baseResults/preprocessor.errors.vert.out | 16 --- .../preprocessor.extensions.vert.err | 4 + .../preprocessor.function_macro.vert.err | 2 + Test/baseResults/preprocessor.line.vert.err | 0 Test/baseResults/preprocessor.pragma.vert.err | 2 + Test/baseResults/preprocessor.simple.vert.err | 2 + ...essor.success_if_parse_would_fail.vert.err | 0 ...essor.success_if_parse_would_fail.vert.out | 4 + Test/preprocessor.errors.vert | 9 +- ...processor.success_if_parse_would_fail.vert | 4 + Test/runtests | 3 +- Test/test-preprocessor-list | 1 + glslang/MachineIndependent/ParseHelper.cpp | 69 +++++++---- glslang/MachineIndependent/ParseHelper.h | 7 ++ glslang/MachineIndependent/ShaderLang.cpp | 8 +- .../MachineIndependent/preprocessor/Pp.cpp | 108 +++++++++--------- .../preprocessor/PpScanner.cpp | 50 ++++---- glslang/Public/ShaderLang.h | 1 + 21 files changed, 205 insertions(+), 135 deletions(-) create mode 100644 Test/baseResults/preprocessor.edge_cases.vert.err create mode 100644 Test/baseResults/preprocessor.errors.vert.err create mode 100644 Test/baseResults/preprocessor.extensions.vert.err create mode 100644 Test/baseResults/preprocessor.function_macro.vert.err create mode 100644 Test/baseResults/preprocessor.line.vert.err create mode 100644 Test/baseResults/preprocessor.pragma.vert.err create mode 100644 Test/baseResults/preprocessor.simple.vert.err create mode 100644 Test/baseResults/preprocessor.success_if_parse_would_fail.vert.err create mode 100644 Test/baseResults/preprocessor.success_if_parse_would_fail.vert.out create mode 100644 Test/preprocessor.success_if_parse_would_fail.vert diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index f61389c5c..b88d8ad5e 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -611,6 +611,8 @@ void SetMessageOptions(EShMessages& messages) messages = (EShMessages)(messages | EShMsgSpvRules); if (Options & EOptionVulkanRules) messages = (EShMessages)(messages | EShMsgVulkanRules); + if (Options & EOptionOutputPreprocessed) + messages = (EShMessages)(messages | EShMsgOnlyPreprocessor); } // @@ -645,13 +647,22 @@ const char* GlslStd450DebugNames[GLSL_STD_450::Count]; // Outputs the given string, but only if it is non-null and non-empty. // This prevents erroneous newlines from appearing. -void puts_if_non_empty(const char* str) +void PutsIfNonEmpty(const char* str) { if (str && str[0]) { puts(str); } } +// Outputs the given string to stderr, but only if it is non-null and non-empty. +// This prevents erroneous newlines from appearing. +void StderrIfNonEmpty(const char* str) +{ + if (str && str[0]) { + fprintf(stderr, "%s\n", str); + } +} + // // For linking mode: Will independently parse each item in the worklist, but then put them // in the same program and link them together. @@ -689,8 +700,14 @@ void CompileAndLinkShaders() shader->setStrings(shaderStrings, 1); if (Options & EOptionOutputPreprocessed) { std::string str; - shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false, messages, &str); - puts(str.c_str()); + if (shader->preprocess(&Resources, defaultVersion, ENoProfile, + false, false, messages, &str)) { + PutsIfNonEmpty(str.c_str()); + } else { + CompileFailed = true; + } + StderrIfNonEmpty(shader->getInfoLog()); + StderrIfNonEmpty(shader->getInfoDebugLog()); FreeFileData(shaderStrings); continue; } @@ -700,9 +717,9 @@ void CompileAndLinkShaders() program.addShader(shader); if (! (Options & EOptionSuppressInfolog)) { - puts_if_non_empty(workItem->name.c_str()); - puts_if_non_empty(shader->getInfoLog()); - puts_if_non_empty(shader->getInfoDebugLog()); + PutsIfNonEmpty(workItem->name.c_str()); + PutsIfNonEmpty(shader->getInfoLog()); + PutsIfNonEmpty(shader->getInfoDebugLog()); } FreeFileData(shaderStrings); @@ -716,8 +733,8 @@ void CompileAndLinkShaders() LinkFailed = true; if (! (Options & EOptionSuppressInfolog)) { - puts_if_non_empty(program.getInfoLog()); - puts_if_non_empty(program.getInfoDebugLog()); + PutsIfNonEmpty(program.getInfoLog()); + PutsIfNonEmpty(program.getInfoDebugLog()); } if (Options & EOptionDumpReflection) { @@ -814,8 +831,8 @@ int C_DECL main(int argc, char* argv[]) for (int w = 0; w < NumWorkItems; ++w) { if (Work[w]) { if (printShaderNames) - puts_if_non_empty(Work[w]->name.c_str()); - puts_if_non_empty(Work[w]->results.c_str()); + PutsIfNonEmpty(Work[w]->name.c_str()); + PutsIfNonEmpty(Work[w]->results.c_str()); delete Work[w]; } } @@ -943,7 +960,8 @@ void usage() " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n" " default file name is .spv (-o overrides this)\n" " -H print human readable form of SPIR-V; turns on -V\n" - " -E print pre-processed GLSL; cannot be used with -l.\n" + " -E print pre-processed GLSL; cannot be used with -l;\n" + " errors will appear on stderr.\n" " -c configuration dump;\n" " creates the default configuration file (redirect to a .conf file)\n" " -d default to desktop (#version 110) when there is no shader #version\n" diff --git a/Test/baseResults/preprocessor.edge_cases.vert.err b/Test/baseResults/preprocessor.edge_cases.vert.err new file mode 100644 index 000000000..59674286b --- /dev/null +++ b/Test/baseResults/preprocessor.edge_cases.vert.err @@ -0,0 +1,2 @@ +Warning, version 310 is not yet complete; most version-specific features are present, but some are missing. + diff --git a/Test/baseResults/preprocessor.errors.vert.err b/Test/baseResults/preprocessor.errors.vert.err new file mode 100644 index 000000000..7da61a0aa --- /dev/null +++ b/Test/baseResults/preprocessor.errors.vert.err @@ -0,0 +1,8 @@ +Warning, version 310 is not yet complete; most version-specific features are present, but some are missing. +ERROR: 0:9: '#error' : This should show up in pp output . +ERROR: 0:14: '#' : invalid directive: def +ERROR: 0:15: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile Y +ERROR: 0:21: '' : missing #endif +ERROR: 4 compilation errors. No code generated. + + diff --git a/Test/baseResults/preprocessor.errors.vert.out b/Test/baseResults/preprocessor.errors.vert.out index e0cabb85f..e69de29bb 100644 --- a/Test/baseResults/preprocessor.errors.vert.out +++ b/Test/baseResults/preprocessor.errors.vert.out @@ -1,16 +0,0 @@ -#version 310 es - - - - - - - -#error This should show up in pp output . - - - - -int main(){ -} - diff --git a/Test/baseResults/preprocessor.extensions.vert.err b/Test/baseResults/preprocessor.extensions.vert.err new file mode 100644 index 000000000..03b9ff9cc --- /dev/null +++ b/Test/baseResults/preprocessor.extensions.vert.err @@ -0,0 +1,4 @@ +Warning, version 310 is not yet complete; most version-specific features are present, but some are missing. +WARNING: 0:5: '#extension' : extension is only partially supported: GL_EXT_gpu_shader5 +WARNING: 0:6: '#extension' : extension not supported: GL_EXT_shader_texture_image_samples + diff --git a/Test/baseResults/preprocessor.function_macro.vert.err b/Test/baseResults/preprocessor.function_macro.vert.err new file mode 100644 index 000000000..59674286b --- /dev/null +++ b/Test/baseResults/preprocessor.function_macro.vert.err @@ -0,0 +1,2 @@ +Warning, version 310 is not yet complete; most version-specific features are present, but some are missing. + diff --git a/Test/baseResults/preprocessor.line.vert.err b/Test/baseResults/preprocessor.line.vert.err new file mode 100644 index 000000000..e69de29bb diff --git a/Test/baseResults/preprocessor.pragma.vert.err b/Test/baseResults/preprocessor.pragma.vert.err new file mode 100644 index 000000000..59674286b --- /dev/null +++ b/Test/baseResults/preprocessor.pragma.vert.err @@ -0,0 +1,2 @@ +Warning, version 310 is not yet complete; most version-specific features are present, but some are missing. + diff --git a/Test/baseResults/preprocessor.simple.vert.err b/Test/baseResults/preprocessor.simple.vert.err new file mode 100644 index 000000000..59674286b --- /dev/null +++ b/Test/baseResults/preprocessor.simple.vert.err @@ -0,0 +1,2 @@ +Warning, version 310 is not yet complete; most version-specific features are present, but some are missing. + diff --git a/Test/baseResults/preprocessor.success_if_parse_would_fail.vert.err b/Test/baseResults/preprocessor.success_if_parse_would_fail.vert.err new file mode 100644 index 000000000..e69de29bb diff --git a/Test/baseResults/preprocessor.success_if_parse_would_fail.vert.out b/Test/baseResults/preprocessor.success_if_parse_would_fail.vert.out new file mode 100644 index 000000000..624813a01 --- /dev/null +++ b/Test/baseResults/preprocessor.success_if_parse_would_fail.vert.out @@ -0,0 +1,4 @@ +int x(){ + something that shouldnt compile; +} + diff --git a/Test/preprocessor.errors.vert b/Test/preprocessor.errors.vert index 7de504039..ca83848fa 100644 --- a/Test/preprocessor.errors.vert +++ b/Test/preprocessor.errors.vert @@ -1,9 +1,9 @@ #version 310 es -#define X +#define X 1 #if X - #if Y + #ifdef Y #error This should not show up in pp output. #endif #error This should show up in pp output. @@ -11,5 +11,10 @@ #error This should not show up in pp output. #endif +#def X +#if Y + +#extension a + int main() { } diff --git a/Test/preprocessor.success_if_parse_would_fail.vert b/Test/preprocessor.success_if_parse_would_fail.vert new file mode 100644 index 000000000..ed1ad0c0e --- /dev/null +++ b/Test/preprocessor.success_if_parse_would_fail.vert @@ -0,0 +1,4 @@ +int x() { + something that shouldnt compile; +} + diff --git a/Test/runtests b/Test/runtests index db2a345cb..ea881bcc4 100755 --- a/Test/runtests +++ b/Test/runtests @@ -61,8 +61,9 @@ rm -f comp.spv frag.spv geom.spv tesc.spv tese.spv vert.spv while read t; do echo Running Preprocessor $t... b=`basename $t` - $EXE -E $t > $TARGETDIR/$b.out + $EXE -E $t > $TARGETDIR/$b.out 2> $TARGETDIR/$b.err diff -b $BASEDIR/$b.out $TARGETDIR/$b.out || HASERROR=1 + diff -b $BASEDIR/$b.err $TARGETDIR/$b.err || HASERROR=1 done < test-preprocessor-list # diff --git a/Test/test-preprocessor-list b/Test/test-preprocessor-list index b35d03f46..1baa55846 100644 --- a/Test/test-preprocessor-list +++ b/Test/test-preprocessor-list @@ -5,3 +5,4 @@ preprocessor.function_macro.vert preprocessor.line.vert preprocessor.pragma.vert preprocessor.simple.vert +preprocessor.success_if_parse_would_fail.vert diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 34d3fbfc7..8753aa626 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -341,24 +341,35 @@ bool TParseContext::parseVectorFields(TSourceLoc loc, const TString& compString, // // Used to output syntax, parsing, and semantic errors. // -void C_DECL TParseContext::error(TSourceLoc loc, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) + +void TParseContext::outputMessage(TSourceLoc loc, const char* szReason, + const char* szToken, + const char* szExtraInfoFormat, + TPrefixType prefix, va_list args) { const int maxSize = GlslangMaxTokenLength + 200; char szExtraInfo[maxSize]; - va_list marker; - va_start(marker, szExtraInfoFormat); + safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); - safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, marker); - - infoSink.info.prefix(EPrefixError); + infoSink.info.prefix(prefix); infoSink.info.location(loc); infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; - va_end(marker); + if (prefix == EPrefixError) { + ++numErrors; + } +} - ++numErrors; +void C_DECL TParseContext::error(TSourceLoc loc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) +{ + if (messages & EShMsgOnlyPreprocessor) + return; + va_list args; + va_start(args, szExtraInfoFormat); + outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); + va_end(args); } void C_DECL TParseContext::warn(TSourceLoc loc, const char* szReason, const char* szToken, @@ -366,20 +377,28 @@ void C_DECL TParseContext::warn(TSourceLoc loc, const char* szReason, const char { if (suppressWarnings()) return; + va_list args; + va_start(args, szExtraInfoFormat); + outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); + va_end(args); +} - const int maxSize = GlslangMaxTokenLength + 200; - char szExtraInfo[maxSize]; - va_list marker; +void C_DECL TParseContext::ppError(TSourceLoc loc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) +{ + va_list args; + va_start(args, szExtraInfoFormat); + outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); + va_end(args); +} - va_start(marker, szExtraInfoFormat); - - safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, marker); - - infoSink.info.prefix(EPrefixWarning); - infoSink.info.location(loc); - infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; - - va_end(marker); +void C_DECL TParseContext::ppWarn(TSourceLoc loc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) +{ + va_list args; + va_start(args, szExtraInfoFormat); + outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); + va_end(args); } // @@ -1815,18 +1834,18 @@ void TParseContext::reservedPpErrorCheck(TSourceLoc loc, const char* identifier, // compile-time error." // however, before that, ES tests required an error. if (strncmp(identifier, "GL_", 3) == 0) - error(loc, "names beginning with \"GL_\" can't be (un)defined:", op, identifier); + ppError(loc, "names beginning with \"GL_\" can't be (un)defined:", op, identifier); else if (strstr(identifier, "__") != 0) { if (profile == EEsProfile && version >= 300 && (strcmp(identifier, "__LINE__") == 0 || strcmp(identifier, "__FILE__") == 0 || strcmp(identifier, "__VERSION__") == 0)) - error(loc, "predefined names can't be (un)defined:", op, identifier); + ppError(loc, "predefined names can't be (un)defined:", op, identifier); else { if (profile == EEsProfile && version <= 300) - error(loc, "names containing consecutive underscores are reserved, and an error if version <= 300:", op, identifier); + ppError(loc, "names containing consecutive underscores are reserved, and an error if version <= 300:", op, identifier); else - warn(loc, "names containing consecutive underscores are reserved:", op, identifier); + ppWarn(loc, "names containing consecutive underscores are reserved:", op, identifier); } } } diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 3d933d9f6..672a6e010 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -78,6 +78,10 @@ public: const char* szExtraInfoFormat, ...); void C_DECL warn(TSourceLoc, const char* szReason, const char* szToken, const char* szExtraInfoFormat, ...); + void C_DECL ppError(TSourceLoc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...); + void C_DECL ppWarn(TSourceLoc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...); bool relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; } bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; } @@ -249,6 +253,9 @@ protected: TOperator mapTypeToConstructorOp(const TType&) const; void updateExtensionBehavior(const char* const extension, TExtensionBehavior); void finalErrorCheck(); + void outputMessage(TSourceLoc, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, TPrefixType prefix, + va_list args); public: // diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index a1516a011..a58cbff60 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -714,7 +714,13 @@ struct DoPreprocessing { outputStream << std::endl; *outputString = outputStream.str(); - return true; + bool success = true; + if (parseContext.getNumErrors() > 0) { + success = false; + parseContext.infoSink.info.prefix(EPrefixError); + parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors. No code generated.\n\n"; + } + return success; } std::string* outputString; }; diff --git a/glslang/MachineIndependent/preprocessor/Pp.cpp b/glslang/MachineIndependent/preprocessor/Pp.cpp index 6b8cdc0a0..1d03b43b8 100644 --- a/glslang/MachineIndependent/preprocessor/Pp.cpp +++ b/glslang/MachineIndependent/preprocessor/Pp.cpp @@ -134,7 +134,7 @@ int TPpContext::CPPdefine(TPpToken* ppToken) // get macro name int token = scanToken(ppToken); if (token != CPP_IDENTIFIER) { - parseContext.error(ppToken->loc, "must be followed by macro name", "#define", ""); + parseContext.ppError(ppToken->loc, "must be followed by macro name", "#define", ""); return token; } int atom = ppToken->atom; @@ -154,7 +154,7 @@ int TPpContext::CPPdefine(TPpToken* ppToken) if (argc == 0 && token == ')') break; if (token != CPP_IDENTIFIER) { - parseContext.error(ppToken->loc, "bad argument", "#define", ""); + parseContext.ppError(ppToken->loc, "bad argument", "#define", ""); return token; } @@ -162,7 +162,7 @@ int TPpContext::CPPdefine(TPpToken* ppToken) bool duplicate = false; for (int a = 0; a < argc; ++a) { if (args[a] == ppToken->atom) { - parseContext.error(ppToken->loc, "duplicate macro parameter", "#define", ""); + parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", ""); duplicate = true; break; } @@ -171,12 +171,12 @@ int TPpContext::CPPdefine(TPpToken* ppToken) if (argc < maxMacroArgs) args[argc++] = ppToken->atom; else - parseContext.error(ppToken->loc, "too many macro parameters", "#define", ""); + parseContext.ppError(ppToken->loc, "too many macro parameters", "#define", ""); } token = scanToken(ppToken); } while (token == ','); if (token != ')') { - parseContext.error(ppToken->loc, "missing parenthesis", "#define", ""); + parseContext.ppError(ppToken->loc, "missing parenthesis", "#define", ""); return token; } @@ -204,11 +204,11 @@ int TPpContext::CPPdefine(TPpToken* ppToken) // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number, // ordering, spelling, and white-space separation, where all white-space separations are considered identical." if (symb->mac.argc != mac.argc) - parseContext.error(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(atom)); + parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(atom)); else { for (int argc = 0; argc < mac.argc; argc++) { if (symb->mac.args[argc] != mac.args[argc]) - parseContext.error(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(atom)); + parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(atom)); } RewindTokenStream(symb->mac.body); RewindTokenStream(mac.body); @@ -220,7 +220,7 @@ int TPpContext::CPPdefine(TPpToken* ppToken) oldToken = ReadToken(symb->mac.body, &oldPpToken); newToken = ReadToken(mac.body, &newPpToken); if (oldToken != newToken || oldPpToken != newPpToken) { - parseContext.error(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(atom)); + parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(atom)); break; } } while (newToken > 0); @@ -241,7 +241,7 @@ int TPpContext::CPPundef(TPpToken* ppToken) int token = scanToken(ppToken); Symbol *symb; if (token != CPP_IDENTIFIER) { - parseContext.error(ppToken->loc, "must be followed by macro name", "#undef", ""); + parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", ""); return token; } @@ -255,7 +255,7 @@ int TPpContext::CPPundef(TPpToken* ppToken) } token = scanToken(ppToken); if (token != '\n') - parseContext.error(ppToken->loc, "can only be followed by a single macro name", "#undef", ""); + parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", ""); return token; } @@ -311,7 +311,7 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken) break; } else if (atom == elifAtom) { if (elseSeen[elsetracker]) - parseContext.error(ppToken->loc, "#elif after #else", "#elif", ""); + parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); /* we decrement ifdepth here, because CPPif will increment * it and we really want to leave it alone */ if (ifdepth) { @@ -324,13 +324,13 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken) } } else if (atom == elseAtom) { if (elseSeen[elsetracker]) - parseContext.error(ppToken->loc, "#else after #else", "#else", ""); + parseContext.ppError(ppToken->loc, "#else after #else", "#else", ""); else elseSeen[elsetracker] = true; token = extraTokenCheck(atom, ppToken, scanToken(ppToken)); } else if (atom == elifAtom) { if (elseSeen[elsetracker]) - parseContext.error(ppToken->loc, "#elif after #else", "#elif", ""); + parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); } } @@ -358,9 +358,9 @@ int TPpContext::extraTokenCheck(int atom, TPpToken* ppToken, int token) label = ""; if (parseContext.relaxedErrors()) - parseContext.warn(ppToken->loc, message, label, ""); + parseContext.ppWarn(ppToken->loc, message, label, ""); else - parseContext.error(ppToken->loc, message, label, ""); + parseContext.ppError(ppToken->loc, message, label, ""); while (token != '\n') token = scanToken(ppToken); @@ -448,7 +448,7 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo token = scanToken(ppToken); } if (token != CPP_IDENTIFIER) { - parseContext.error(loc, "incorrect directive, expected identifier", "preprocessor evaluation", ""); + parseContext.ppError(loc, "incorrect directive, expected identifier", "preprocessor evaluation", ""); err = true; res = 0; @@ -459,7 +459,7 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo token = scanToken(ppToken); if (needclose) { if (token != ')') { - parseContext.error(loc, "expected ')'", "preprocessor evaluation", ""); + parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", ""); err = true; res = 0; @@ -479,7 +479,7 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken); if (! err) { if (token != ')') { - parseContext.error(loc, "expected ')'", "preprocessor evaluation", ""); + parseContext.ppError(loc, "expected ')'", "preprocessor evaluation", ""); err = true; res = 0; @@ -498,7 +498,7 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo token = eval(token, UNARY, shortCircuit, res, err, ppToken); res = unop[op].op(res); } else { - parseContext.error(loc, "bad expression", "preprocessor evaluation", ""); + parseContext.ppError(loc, "bad expression", "preprocessor evaluation", ""); err = true; res = 0; @@ -543,7 +543,7 @@ int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, T while (token == CPP_IDENTIFIER && ppToken->atom != definedAtom) { int macroReturn = MacroExpand(ppToken->atom, ppToken, true, false); if (macroReturn == 0) { - parseContext.error(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", ""); + parseContext.ppError(ppToken->loc, "can't evaluate expression", "preprocessor evaluation", ""); err = true; res = 0; token = scanToken(ppToken); @@ -554,9 +554,9 @@ int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, T const char* message = "undefined macro in expression not allowed in es profile"; const char* name = GetAtomString(ppToken->atom); if (parseContext.relaxedErrors()) - parseContext.warn(ppToken->loc, message, "preprocessor evaluation", name); + parseContext.ppWarn(ppToken->loc, message, "preprocessor evaluation", name); else - parseContext.error(ppToken->loc, message, "preprocessor evaluation", name); + parseContext.ppError(ppToken->loc, message, "preprocessor evaluation", name); } } token = scanToken(ppToken); @@ -573,7 +573,7 @@ int TPpContext::CPPif(TPpToken* ppToken) if (! ifdepth++) ifloc = ppToken->loc; if (ifdepth > maxIfNesting) { - parseContext.error(ppToken->loc, "maximum nesting depth exceeded", "#if", ""); + parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", ""); return 0; } int res = 0; @@ -592,20 +592,20 @@ int TPpContext::CPPifdef(int defined, TPpToken* ppToken) int token = scanToken(ppToken); int name = ppToken->atom; if (++ifdepth > maxIfNesting) { - parseContext.error(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", ""); + parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", ""); return 0; } elsetracker++; if (token != CPP_IDENTIFIER) { if (defined) - parseContext.error(ppToken->loc, "must be followed by macro name", "#ifdef", ""); + parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", ""); else - parseContext.error(ppToken->loc, "must be followed by macro name", "#ifndef", ""); + parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", ""); } else { Symbol *s = LookUpSymbol(name); token = scanToken(ppToken); if (token != '\n') { - parseContext.error(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", ""); + parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", ""); while (token != '\n') token = scanToken(ppToken); } @@ -625,7 +625,7 @@ int TPpContext::CPPline(TPpToken* ppToken) int token = scanToken(ppToken); if (token == '\n') { - parseContext.error(ppToken->loc, "must by followed by an integral literal", "#line", ""); + parseContext.ppError(ppToken->loc, "must by followed by an integral literal", "#line", ""); return token; } @@ -688,7 +688,7 @@ int TPpContext::CPPerror(TPpToken* ppToken) } parseContext.notifyErrorDirective(loc.line, message.c_str()); //store this msg into the shader's information log..set the Compile Error flag!!!! - parseContext.error(loc, message.c_str(), "#error", ""); + parseContext.ppError(loc, message.c_str(), "#error", ""); return '\n'; } @@ -724,7 +724,7 @@ int TPpContext::CPPpragma(TPpToken* ppToken) } if (token == EOF) - parseContext.error(loc, "directive must end with a newline", "#pragma", ""); + parseContext.ppError(loc, "directive must end with a newline", "#pragma", ""); else parseContext.handlePragma(loc, tokens); @@ -737,17 +737,17 @@ int TPpContext::CPPversion(TPpToken* ppToken) int token = scanToken(ppToken); if (errorOnVersion || versionSeen) - parseContext.error(ppToken->loc, "must occur first in shader", "#version", ""); + parseContext.ppError(ppToken->loc, "must occur first in shader", "#version", ""); versionSeen = true; if (token == '\n') { - parseContext.error(ppToken->loc, "must be followed by version number", "#version", ""); + parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", ""); return token; } if (token != CPP_INTCONSTANT) - parseContext.error(ppToken->loc, "must be followed by version number", "#version", ""); + parseContext.ppError(ppToken->loc, "must be followed by version number", "#version", ""); ppToken->ival = atoi(ppToken->name); int versionNumber = ppToken->ival; @@ -761,14 +761,14 @@ int TPpContext::CPPversion(TPpToken* ppToken) if (ppToken->atom != coreAtom && ppToken->atom != compatibilityAtom && ppToken->atom != esAtom) - parseContext.error(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", ""); + parseContext.ppError(ppToken->loc, "bad profile name; use es, core, or compatibility", "#version", ""); parseContext.notifyVersion(line, versionNumber, GetAtomString(ppToken->atom)); token = scanToken(ppToken); if (token == '\n') return token; else - parseContext.error(ppToken->loc, "bad tokens following profile -- expected newline", "#version", ""); + parseContext.ppError(ppToken->loc, "bad tokens following profile -- expected newline", "#version", ""); } return token; @@ -782,24 +782,24 @@ int TPpContext::CPPextension(TPpToken* ppToken) char extensionName[80]; if (token=='\n') { - parseContext.error(ppToken->loc, "extension name not specified", "#extension", ""); + parseContext.ppError(ppToken->loc, "extension name not specified", "#extension", ""); return token; } if (token != CPP_IDENTIFIER) - parseContext.error(ppToken->loc, "extension name expected", "#extension", ""); + parseContext.ppError(ppToken->loc, "extension name expected", "#extension", ""); strcpy(extensionName, GetAtomString(ppToken->atom)); token = scanToken(ppToken); if (token != ':') { - parseContext.error(ppToken->loc, "':' missing after extension name", "#extension", ""); + parseContext.ppError(ppToken->loc, "':' missing after extension name", "#extension", ""); return token; } token = scanToken(ppToken); if (token != CPP_IDENTIFIER) { - parseContext.error(ppToken->loc, "behavior for extension not specified", "#extension", ""); + parseContext.ppError(ppToken->loc, "behavior for extension not specified", "#extension", ""); return token; } @@ -809,7 +809,7 @@ int TPpContext::CPPextension(TPpToken* ppToken) if (token == '\n') return token; else - parseContext.error(ppToken->loc, "extra tokens -- expected newline", "#extension",""); + parseContext.ppError(ppToken->loc, "extra tokens -- expected newline", "#extension",""); return token; } @@ -823,17 +823,17 @@ int TPpContext::readCPPline(TPpToken* ppToken) token = CPPdefine(ppToken); } else if (ppToken->atom == elseAtom) { if (elsetracker[elseSeen]) - parseContext.error(ppToken->loc, "#else after #else", "#else", ""); + parseContext.ppError(ppToken->loc, "#else after #else", "#else", ""); elsetracker[elseSeen] = true; if (! ifdepth) - parseContext.error(ppToken->loc, "mismatched statements", "#else", ""); + parseContext.ppError(ppToken->loc, "mismatched statements", "#else", ""); token = extraTokenCheck(elseAtom, ppToken, scanToken(ppToken)); token = CPPelse(0, ppToken); } else if (ppToken->atom == elifAtom) { if (! ifdepth) - parseContext.error(ppToken->loc, "mismatched statements", "#elif", ""); + parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", ""); if (elseSeen[elsetracker]) - parseContext.error(ppToken->loc, "#elif after #else", "#elif", ""); + parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", ""); // this token is really a dont care, but we still need to eat the tokens token = scanToken(ppToken); while (token != '\n') @@ -843,7 +843,7 @@ int TPpContext::readCPPline(TPpToken* ppToken) elseSeen[elsetracker] = false; --elsetracker; if (! ifdepth) - parseContext.error(ppToken->loc, "mismatched statements", "#endif", ""); + parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", ""); else --ifdepth; token = extraTokenCheck(endifAtom, ppToken, scanToken(ppToken)); @@ -866,10 +866,10 @@ int TPpContext::readCPPline(TPpToken* ppToken) } else if (ppToken->atom == extensionAtom) { token = CPPextension(ppToken); } else { - parseContext.error(ppToken->loc, "invalid directive:", "#", GetAtomString(ppToken->atom)); + parseContext.ppError(ppToken->loc, "invalid directive:", "#", GetAtomString(ppToken->atom)); } } else if (token != '\n' && token != EOF) - parseContext.error(ppToken->loc, "invalid directive", "#", ""); + parseContext.ppError(ppToken->loc, "invalid directive", "#", ""); while (token != '\n' && token != 0 && token != EOF) token = scanToken(ppToken); @@ -1012,7 +1012,7 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool token = scanToken(ppToken); } if (token != '(') { - parseContext.error(loc, "expected '(' following", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "expected '(' following", "macro expansion", GetAtomString(atom)); UngetToken(token, ppToken); ppToken->atom = atom; @@ -1029,20 +1029,20 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool while (1) { token = scanToken(ppToken); if (token == EOF) { - parseContext.error(loc, "EOF in macro", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "EOF in macro", "macro expansion", GetAtomString(atom)); delete in; return 0; } if (token == '\n') { if (! newLineOkay) { - parseContext.error(loc, "end of line in macro substitution:", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "end of line in macro substitution:", "macro expansion", GetAtomString(atom)); delete in; return 0; } continue; } if (token == '#') { - parseContext.error(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom)); + parseContext.ppError(ppToken->loc, "unexpected '#'", "macro expansion", GetAtomString(atom)); delete in; return 0; } @@ -1067,7 +1067,7 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool } while (arg < in->mac->argc); if (arg < in->mac->argc) - parseContext.error(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom)); else if (token != ')') { depth=0; while (token != EOF && (depth > 0 || token != ')')) { @@ -1079,11 +1079,11 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool } if (token == EOF) { - parseContext.error(loc, "EOF in macro", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "EOF in macro", "macro expansion", GetAtomString(atom)); delete in; return 0; } - parseContext.error(loc, "Too many args in macro", "macro expansion", GetAtomString(atom)); + parseContext.ppError(loc, "Too many args in macro", "macro expansion", GetAtomString(atom)); } for (int i = 0; i < in->mac->argc; i++) in->args[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay); diff --git a/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/glslang/MachineIndependent/preprocessor/PpScanner.cpp index 445eb3053..7b04221c9 100644 --- a/glslang/MachineIndependent/preprocessor/PpScanner.cpp +++ b/glslang/MachineIndependent/preprocessor/PpScanner.cpp @@ -138,7 +138,7 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) } ch = getChar(); } else { - parseContext.error(ppToken->loc, "float literal too long", "", ""); + parseContext.PpError(ppToken->loc, "float literal too long", "", ""); len = 1; str_len = 1; } @@ -150,7 +150,7 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) if (ch == 'e' || ch == 'E') { HasDecimalOrExponent = true; if (len >= TPpToken::maxTokenLength) { - parseContext.error(ppToken->loc, "float literal too long", "", ""); + parseContext.PpError(ppToken->loc, "float literal too long", "", ""); len = 1; str_len = 1; } else { @@ -169,13 +169,13 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) str[len++] = (char)ch; ch = getChar(); } else { - parseContext.error(ppToken->loc, "float literal too long", "", ""); + parseContext.PpError(ppToken->loc, "float literal too long", "", ""); len = 1; str_len = 1; } } } else { - parseContext.error(ppToken->loc, "bad character in float exponent", "", ""); + parseContext.PpError(ppToken->loc, "bad character in float exponent", "", ""); } } } @@ -187,7 +187,7 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) if (ch == 'l' || ch == 'L') { parseContext.doubleCheck(ppToken->loc, "double floating-point suffix"); if (! HasDecimalOrExponent) - parseContext.error(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); + parseContext.PpError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); int ch2 = getChar(); if (ch2 != 'f' && ch2 != 'F') { ungetChar(); @@ -198,7 +198,7 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) str[len++] = (char)ch2; isDouble = 1; } else { - parseContext.error(ppToken->loc, "float literal too long", "", ""); + parseContext.PpError(ppToken->loc, "float literal too long", "", ""); len = 1,str_len=1; } } @@ -207,11 +207,11 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) if (! parseContext.relaxedErrors()) parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix"); if (! HasDecimalOrExponent) - parseContext.error(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); + parseContext.PpError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); if (len < TPpToken::maxTokenLength) str[len++] = (char)ch; else { - parseContext.error(ppToken->loc, "float literal too long", "", ""); + parseContext.PpError(ppToken->loc, "float literal too long", "", ""); len = 1,str_len=1; } } else @@ -276,7 +276,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ch = pp->getChar(); } else { if (! AlreadyComplained) { - pp->parseContext.error(ppToken->loc, "name too long", "", ""); + pp->parseContext.PpError(ppToken->loc, "name too long", "", ""); AlreadyComplained = 1; } ch = pp->getChar(); @@ -319,11 +319,11 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) } else if (ch >= 'a' && ch <= 'f') { ii = ch - 'a' + 10; } else - pp->parseContext.error(ppToken->loc, "bad digit in hexidecimal literal", "", ""); + pp->parseContext.PpError(ppToken->loc, "bad digit in hexidecimal literal", "", ""); ival = (ival << 4) | ii; } else { if (! AlreadyComplained) { - pp->parseContext.error(ppToken->loc, "hexidecimal literal too big", "", ""); + pp->parseContext.PpError(ppToken->loc, "hexidecimal literal too big", "", ""); AlreadyComplained = 1; } ival = 0xffffffff; @@ -333,7 +333,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')); } else { - pp->parseContext.error(ppToken->loc, "bad digit in hexidecimal literal", "", ""); + pp->parseContext.PpError(ppToken->loc, "bad digit in hexidecimal literal", "", ""); } if (ch == 'u' || ch == 'U') { if (len < TPpToken::maxTokenLength) @@ -361,7 +361,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (len < TPpToken::maxTokenLength) ppToken->name[len++] = (char)ch; else if (! AlreadyComplained) { - pp->parseContext.error(ppToken->loc, "numeric literal too long", "", ""); + pp->parseContext.PpError(ppToken->loc, "numeric literal too long", "", ""); AlreadyComplained = 1; } if (ival <= 0x1fffffff) { @@ -379,7 +379,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (len < TPpToken::maxTokenLength) ppToken->name[len++] = (char)ch; else if (! AlreadyComplained) { - pp->parseContext.error(ppToken->loc, "numeric literal too long", "", ""); + pp->parseContext.PpError(ppToken->loc, "numeric literal too long", "", ""); AlreadyComplained = 1; } ch = pp->getChar(); @@ -390,7 +390,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) // wasn't a float, so must be octal... if (nonOctal) - pp->parseContext.error(ppToken->loc, "octal literal digit too large", "", ""); + pp->parseContext.PpError(ppToken->loc, "octal literal digit too large", "", ""); if (ch == 'u' || ch == 'U') { if (len < TPpToken::maxTokenLength) @@ -401,7 +401,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ppToken->name[len] = '\0'; if (octalOverflow) - pp->parseContext.error(ppToken->loc, "octal literal too big", "", ""); + pp->parseContext.PpError(ppToken->loc, "octal literal too big", "", ""); ppToken->ival = (int)ival; @@ -419,7 +419,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (len < TPpToken::maxTokenLength) ppToken->name[len++] = (char)ch; else if (! AlreadyComplained) { - pp->parseContext.error(ppToken->loc, "numeric literal too long", "", ""); + pp->parseContext.PpError(ppToken->loc, "numeric literal too long", "", ""); AlreadyComplained = 1; } ch = pp->getChar(); @@ -444,7 +444,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) for (int i = 0; i < numericLen; i++) { ch = ppToken->name[i] - '0'; if ((ival > oneTenthMaxInt) || (ival == oneTenthMaxInt && ch > remainderMaxInt)) { - pp->parseContext.error(ppToken->loc, "numeric literal too big", "", ""); + pp->parseContext.PpError(ppToken->loc, "numeric literal too big", "", ""); ival = 0xFFFFFFFFu; break; } else @@ -627,14 +627,14 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) do { while (ch != '*') { if (ch == EOF) { - pp->parseContext.error(ppToken->loc, "EOF in comment", "comment", ""); + pp->parseContext.PpError(ppToken->loc, "EOF in comment", "comment", ""); return endOfInput; } ch = pp->getChar(); } ch = pp->getChar(); if (ch == EOF) { - pp->parseContext.error(ppToken->loc, "EOF in comment", "comment", ""); + pp->parseContext.PpError(ppToken->loc, "EOF in comment", "comment", ""); return endOfInput; } } while (ch != '/'); @@ -663,7 +663,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ppToken->atom = pp->LookUpAddString(tokenText); return CPP_STRCONSTANT; } else { - pp->parseContext.error(ppToken->loc, "end of line in string", "string", ""); + pp->parseContext.PpError(ppToken->loc, "end of line in string", "string", ""); return CPP_ERROR_SY; } } @@ -700,7 +700,7 @@ const char* TPpContext::tokenize(TPpToken* ppToken) } continue; } else { - parseContext.error(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", ""); + parseContext.PpError(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", ""); return nullptr; } } @@ -719,10 +719,10 @@ const char* TPpContext::tokenize(TPpToken* ppToken) token == CPP_FLOATCONSTANT || token == CPP_DOUBLECONSTANT) tokenString = ppToken->name; else if (token == CPP_STRCONSTANT) { - parseContext.error(ppToken->loc, "string literals not supported", "\"\"", ""); + parseContext.PpError(ppToken->loc, "string literals not supported", "\"\"", ""); tokenString = nullptr; } else if (token == '\'') { - parseContext.error(ppToken->loc, "character literals not supported", "\'", ""); + parseContext.PpError(ppToken->loc, "character literals not supported", "\'", ""); tokenString = nullptr; } else tokenString = GetAtomString(token); @@ -740,7 +740,7 @@ const char* TPpContext::tokenize(TPpToken* ppToken) void TPpContext::missingEndifCheck() { if (ifdepth > 0) - parseContext.error(parseContext.getCurrentLoc(), "missing #endif", "", ""); + parseContext.PpError(parseContext.getCurrentLoc(), "missing #endif", "", ""); } } // end namespace glslang diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h index 01a9043c9..d753c8af1 100644 --- a/glslang/Public/ShaderLang.h +++ b/glslang/Public/ShaderLang.h @@ -131,6 +131,7 @@ enum EShMessages { EShMsgAST = (1 << 2), // print the AST intermediate representation EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V + EShMsgOnlyPreprocessor = (1 << 5), // only print out errors produced by the preprocessor }; //