Commit aae1ad82 by Andrew Woloszyn

Added error output to the preprocessor.

This patch distinguishes preprocessing errors with normal parsing errors and gives glslangValidator the ability to output preprocessing errors.
parent 3a194f7b
...@@ -611,6 +611,8 @@ void SetMessageOptions(EShMessages& messages) ...@@ -611,6 +611,8 @@ void SetMessageOptions(EShMessages& messages)
messages = (EShMessages)(messages | EShMsgSpvRules); messages = (EShMessages)(messages | EShMsgSpvRules);
if (Options & EOptionVulkanRules) if (Options & EOptionVulkanRules)
messages = (EShMessages)(messages | EShMsgVulkanRules); messages = (EShMessages)(messages | EShMsgVulkanRules);
if (Options & EOptionOutputPreprocessed)
messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
} }
// //
...@@ -645,13 +647,22 @@ const char* GlslStd450DebugNames[GLSL_STD_450::Count]; ...@@ -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. // Outputs the given string, but only if it is non-null and non-empty.
// This prevents erroneous newlines from appearing. // This prevents erroneous newlines from appearing.
void puts_if_non_empty(const char* str) void PutsIfNonEmpty(const char* str)
{ {
if (str && str[0]) { if (str && str[0]) {
puts(str); 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 // For linking mode: Will independently parse each item in the worklist, but then put them
// in the same program and link them together. // in the same program and link them together.
...@@ -689,8 +700,14 @@ void CompileAndLinkShaders() ...@@ -689,8 +700,14 @@ void CompileAndLinkShaders()
shader->setStrings(shaderStrings, 1); shader->setStrings(shaderStrings, 1);
if (Options & EOptionOutputPreprocessed) { if (Options & EOptionOutputPreprocessed) {
std::string str; std::string str;
shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false, messages, &str); if (shader->preprocess(&Resources, defaultVersion, ENoProfile,
puts(str.c_str()); false, false, messages, &str)) {
PutsIfNonEmpty(str.c_str());
} else {
CompileFailed = true;
}
StderrIfNonEmpty(shader->getInfoLog());
StderrIfNonEmpty(shader->getInfoDebugLog());
FreeFileData(shaderStrings); FreeFileData(shaderStrings);
continue; continue;
} }
...@@ -700,9 +717,9 @@ void CompileAndLinkShaders() ...@@ -700,9 +717,9 @@ void CompileAndLinkShaders()
program.addShader(shader); program.addShader(shader);
if (! (Options & EOptionSuppressInfolog)) { if (! (Options & EOptionSuppressInfolog)) {
puts_if_non_empty(workItem->name.c_str()); PutsIfNonEmpty(workItem->name.c_str());
puts_if_non_empty(shader->getInfoLog()); PutsIfNonEmpty(shader->getInfoLog());
puts_if_non_empty(shader->getInfoDebugLog()); PutsIfNonEmpty(shader->getInfoDebugLog());
} }
FreeFileData(shaderStrings); FreeFileData(shaderStrings);
...@@ -716,8 +733,8 @@ void CompileAndLinkShaders() ...@@ -716,8 +733,8 @@ void CompileAndLinkShaders()
LinkFailed = true; LinkFailed = true;
if (! (Options & EOptionSuppressInfolog)) { if (! (Options & EOptionSuppressInfolog)) {
puts_if_non_empty(program.getInfoLog()); PutsIfNonEmpty(program.getInfoLog());
puts_if_non_empty(program.getInfoDebugLog()); PutsIfNonEmpty(program.getInfoDebugLog());
} }
if (Options & EOptionDumpReflection) { if (Options & EOptionDumpReflection) {
...@@ -814,8 +831,8 @@ int C_DECL main(int argc, char* argv[]) ...@@ -814,8 +831,8 @@ int C_DECL main(int argc, char* argv[])
for (int w = 0; w < NumWorkItems; ++w) { for (int w = 0; w < NumWorkItems; ++w) {
if (Work[w]) { if (Work[w]) {
if (printShaderNames) if (printShaderNames)
puts_if_non_empty(Work[w]->name.c_str()); PutsIfNonEmpty(Work[w]->name.c_str());
puts_if_non_empty(Work[w]->results.c_str()); PutsIfNonEmpty(Work[w]->results.c_str());
delete Work[w]; delete Work[w];
} }
} }
...@@ -943,7 +960,8 @@ void usage() ...@@ -943,7 +960,8 @@ void usage()
" -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n" " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
" default file name is <stage>.spv (-o overrides this)\n" " default file name is <stage>.spv (-o overrides this)\n"
" -H print human readable form of SPIR-V; turns on -V\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" " -c configuration dump;\n"
" creates the default configuration file (redirect to a .conf file)\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" " -d default to desktop (#version 110) when there is no shader #version\n"
......
Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.
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.
#version 310 es
#error This should show up in pp output .
int main(){
}
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
Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.
Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.
Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.
#version 310 es #version 310 es
#define X #define X 1
#if X #if X
#if Y #ifdef Y
#error This should not show up in pp output. #error This should not show up in pp output.
#endif #endif
#error This should show up in pp output. #error This should show up in pp output.
...@@ -11,5 +11,10 @@ ...@@ -11,5 +11,10 @@
#error This should not show up in pp output. #error This should not show up in pp output.
#endif #endif
#def X
#if Y
#extension a
int main() { int main() {
} }
int x() {
something that shouldnt compile;
}
...@@ -61,8 +61,9 @@ rm -f comp.spv frag.spv geom.spv tesc.spv tese.spv vert.spv ...@@ -61,8 +61,9 @@ rm -f comp.spv frag.spv geom.spv tesc.spv tese.spv vert.spv
while read t; do while read t; do
echo Running Preprocessor $t... echo Running Preprocessor $t...
b=`basename $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.out $TARGETDIR/$b.out || HASERROR=1
diff -b $BASEDIR/$b.err $TARGETDIR/$b.err || HASERROR=1
done < test-preprocessor-list done < test-preprocessor-list
# #
......
...@@ -5,3 +5,4 @@ preprocessor.function_macro.vert ...@@ -5,3 +5,4 @@ preprocessor.function_macro.vert
preprocessor.line.vert preprocessor.line.vert
preprocessor.pragma.vert preprocessor.pragma.vert
preprocessor.simple.vert preprocessor.simple.vert
preprocessor.success_if_parse_would_fail.vert
...@@ -341,24 +341,35 @@ bool TParseContext::parseVectorFields(TSourceLoc loc, const TString& compString, ...@@ -341,24 +341,35 @@ bool TParseContext::parseVectorFields(TSourceLoc loc, const TString& compString,
// //
// Used to output syntax, parsing, and semantic errors. // 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; const int maxSize = GlslangMaxTokenLength + 200;
char szExtraInfo[maxSize]; 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(prefix);
infoSink.info.prefix(EPrefixError);
infoSink.info.location(loc); infoSink.info.location(loc);
infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; 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, 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 ...@@ -366,20 +377,28 @@ void C_DECL TParseContext::warn(TSourceLoc loc, const char* szReason, const char
{ {
if (suppressWarnings()) if (suppressWarnings())
return; return;
va_list args;
va_start(args, szExtraInfoFormat);
outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args);
va_end(args);
}
const int maxSize = GlslangMaxTokenLength + 200; void C_DECL TParseContext::ppError(TSourceLoc loc, const char* szReason, const char* szToken,
char szExtraInfo[maxSize]; const char* szExtraInfoFormat, ...)
va_list marker; {
va_list args;
va_start(marker, szExtraInfoFormat); va_start(args, szExtraInfoFormat);
outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args);
safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, marker); va_end(args);
}
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, ...@@ -1815,18 +1834,18 @@ void TParseContext::reservedPpErrorCheck(TSourceLoc loc, const char* identifier,
// compile-time error." // compile-time error."
// however, before that, ES tests required an error. // however, before that, ES tests required an error.
if (strncmp(identifier, "GL_", 3) == 0) 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) { else if (strstr(identifier, "__") != 0) {
if (profile == EEsProfile && version >= 300 && if (profile == EEsProfile && version >= 300 &&
(strcmp(identifier, "__LINE__") == 0 || (strcmp(identifier, "__LINE__") == 0 ||
strcmp(identifier, "__FILE__") == 0 || strcmp(identifier, "__FILE__") == 0 ||
strcmp(identifier, "__VERSION__") == 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 { else {
if (profile == EEsProfile && version <= 300) 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 else
warn(loc, "names containing consecutive underscores are reserved:", op, identifier); ppWarn(loc, "names containing consecutive underscores are reserved:", op, identifier);
} }
} }
} }
......
...@@ -78,6 +78,10 @@ public: ...@@ -78,6 +78,10 @@ public:
const char* szExtraInfoFormat, ...); const char* szExtraInfoFormat, ...);
void C_DECL warn(TSourceLoc, const char* szReason, const char* szToken, void C_DECL warn(TSourceLoc, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...); 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 relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; }
bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; } bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; }
...@@ -249,6 +253,9 @@ protected: ...@@ -249,6 +253,9 @@ protected:
TOperator mapTypeToConstructorOp(const TType&) const; TOperator mapTypeToConstructorOp(const TType&) const;
void updateExtensionBehavior(const char* const extension, TExtensionBehavior); void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
void finalErrorCheck(); void finalErrorCheck();
void outputMessage(TSourceLoc, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, TPrefixType prefix,
va_list args);
public: public:
// //
......
...@@ -714,7 +714,13 @@ struct DoPreprocessing { ...@@ -714,7 +714,13 @@ struct DoPreprocessing {
outputStream << std::endl; outputStream << std::endl;
*outputString = outputStream.str(); *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; std::string* outputString;
}; };
......
...@@ -131,6 +131,7 @@ enum EShMessages { ...@@ -131,6 +131,7 @@ enum EShMessages {
EShMsgAST = (1 << 2), // print the AST intermediate representation EShMsgAST = (1 << 2), // print the AST intermediate representation
EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation
EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V
EShMsgOnlyPreprocessor = (1 << 5), // only print out errors produced by the preprocessor
}; };
// //
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment