Commit 77ba408a by Olli Etuaho Committed by Commit Bot

Unify Diagnostics interface

Use the same kind of interface for reporting preprocessor errors as for reporting regular compiler errors, and make global errors like having too many uniforms also go through Diagnostics. Also don't create std::string objects unnecessarily. Includes cleanups of some dead code related to reporting errors. BUG=angleproject:1670 TEST=angle_unittests Change-Id: I3ee794d32ddeec1826bdf1b76b558f35259f82c0 Reviewed-on: https://chromium-review.googlesource.com/421527Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent a26c6b7c
......@@ -103,6 +103,7 @@
'compiler/translator/ScalarizeVecAndMatConstructorArgs.h',
'compiler/translator/SearchSymbol.cpp',
'compiler/translator/SearchSymbol.h',
'compiler/translator/Severity.h',
'compiler/translator/ShaderLang.cpp',
'compiler/translator/ShaderVars.cpp',
'compiler/translator/SymbolTable.cpp',
......
......@@ -17,23 +17,22 @@ Diagnostics::~Diagnostics()
void Diagnostics::report(ID id, const SourceLocation &loc, const std::string &text)
{
// TODO(alokp): Keep a count of errors and warnings.
print(id, loc, text);
}
Diagnostics::Severity Diagnostics::severity(ID id)
bool Diagnostics::isError(ID id)
{
if ((id > PP_ERROR_BEGIN) && (id < PP_ERROR_END))
return PP_ERROR;
return true;
if ((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END))
return PP_WARNING;
return false;
UNREACHABLE();
return PP_ERROR;
return true;
}
std::string Diagnostics::message(ID id)
const char *Diagnostics::message(ID id)
{
switch (id)
{
......
......@@ -19,11 +19,6 @@ struct SourceLocation;
class Diagnostics
{
public:
enum Severity
{
PP_ERROR,
PP_WARNING
};
enum ID
{
PP_ERROR_BEGIN,
......@@ -83,8 +78,8 @@ class Diagnostics
void report(ID id, const SourceLocation &loc, const std::string &text);
protected:
Severity severity(ID id);
std::string message(ID id);
bool isError(ID id);
const char *message(ID id);
virtual void print(ID id, const SourceLocation &loc, const std::string &text) = 0;
};
......
......@@ -9,7 +9,7 @@
// order.
#include "compiler/translator/CallDAG.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/Diagnostics.h"
namespace sh
{
......@@ -19,9 +19,9 @@ namespace sh
class CallDAG::CallDAGCreator : public TIntermTraverser
{
public:
CallDAGCreator(TInfoSinkBase *info)
CallDAGCreator(TDiagnostics *diagnostics)
: TIntermTraverser(true, false, true),
mCreationInfo(info),
mDiagnostics(diagnostics),
mCurrentFunction(nullptr),
mCurrentIndex(0)
{
......@@ -38,7 +38,6 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
InitResult result = assignIndicesInternal(&it.second);
if (result != INITDAG_SUCCESS)
{
*mCreationInfo << "\n";
return result;
}
}
......@@ -190,6 +189,8 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
InitResult result = INITDAG_SUCCESS;
std::stringstream errorStream;
while (!functionsToProcess.empty())
{
CreatorFunctionData *function = functionsToProcess.back();
......@@ -206,8 +207,8 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
if (!function->node)
{
*mCreationInfo << "Undefined function '" << function->name
<< ")' used in the following call chain:";
errorStream << "Undefined function '" << function->name
<< ")' used in the following call chain:";
result = INITDAG_UNDEFINED;
break;
}
......@@ -228,7 +229,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
// in the chain printed in the info log.
if (callee->visiting)
{
*mCreationInfo << "Recursive function call in the following call chain:";
errorStream << "Recursive function call in the following call chain:";
result = INITDAG_RECURSION;
break;
}
......@@ -250,18 +251,23 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
{
if (!first)
{
*mCreationInfo << " -> ";
errorStream << " -> ";
}
*mCreationInfo << function->name << ")";
errorStream << function->name << ")";
first = false;
}
}
if (mDiagnostics)
{
std::string errorStr = errorStream.str();
mDiagnostics->globalError(errorStr.c_str());
}
}
return result;
}
TInfoSinkBase *mCreationInfo;
TDiagnostics *mDiagnostics;
std::map<TString, CreatorFunctionData> mFunctions;
CreatorFunctionData *mCurrentFunction;
......@@ -318,11 +324,9 @@ void CallDAG::clear()
mFunctionIdToIndex.clear();
}
CallDAG::InitResult CallDAG::init(TIntermNode *root, TInfoSinkBase *info)
CallDAG::InitResult CallDAG::init(TIntermNode *root, TDiagnostics *diagnostics)
{
ASSERT(info);
CallDAGCreator creator(info);
CallDAGCreator creator(diagnostics);
// Creates the mapping of functions to callees
root->traverse(&creator);
......
......@@ -55,8 +55,8 @@ class CallDAG : angle::NonCopyable
};
// Returns INITDAG_SUCCESS if it was able to create the DAG, otherwise prints
// the initialization error in info, if present.
InitResult init(TIntermNode *root, TInfoSinkBase *info);
// the initialization error in diagnostics, if present.
InitResult init(TIntermNode *root, TDiagnostics *diagnostics);
// Returns InvalidIndex if the function wasn't found
size_t findIndex(const TFunctionSymbolInfo *functionInfo) const;
......
......@@ -215,6 +215,7 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
fragmentPrecisionHigh(false),
clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
builtInFunctionEmulator(),
mDiagnostics(infoSink.info),
mSourcePath(NULL),
mComputeShaderLocalSizeDeclared(false),
mTemporaryIndex(0)
......@@ -288,7 +289,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
}
TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
compileOptions, true, infoSink, getResources());
compileOptions, true, &mDiagnostics, getResources());
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
SetGlobalParseContext(&parseContext);
......@@ -305,8 +306,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
shaderVersion = parseContext.getShaderVersion();
if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
{
infoSink.info.prefix(EPrefixError);
infoSink.info << "unsupported shader version";
mDiagnostics.globalError("unsupported shader version");
success = false;
}
......@@ -364,8 +364,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
{
if (!EmulatePrecision::SupportedInLanguage(outputType))
{
infoSink.info.prefix(EPrefixError);
infoSink.info << "Precision emulation not supported for this output type.";
mDiagnostics.globalError("Precision emulation not supported for this output type.");
success = false;
}
}
......@@ -424,8 +423,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
success = enforcePackingRestrictions();
if (!success)
{
infoSink.info.prefix(EPrefixError);
infoSink.info << "too many uniforms";
mDiagnostics.globalError("too many uniforms");
}
}
if (success && (compileOptions & SH_INIT_OUTPUT_VARIABLES))
......@@ -642,6 +640,7 @@ void TCompiler::clearResults()
infoSink.info.erase();
infoSink.obj.erase();
infoSink.debug.erase();
mDiagnostics.resetErrorCount();
attributes.clear();
outputVariables.clear();
......@@ -663,17 +662,14 @@ bool TCompiler::initCallDag(TIntermNode *root)
{
mCallDag.clear();
switch (mCallDag.init(root, &infoSink.info))
switch (mCallDag.init(root, &mDiagnostics))
{
case CallDAG::INITDAG_SUCCESS:
return true;
case CallDAG::INITDAG_RECURSION:
infoSink.info.prefix(EPrefixError);
infoSink.info << "Function recursion detected";
return false;
case CallDAG::INITDAG_UNDEFINED:
infoSink.info.prefix(EPrefixError);
infoSink.info << "Unimplemented function detected";
// Error message has already been written out.
ASSERT(mDiagnostics.numErrors() > 0);
return false;
}
......@@ -700,16 +696,16 @@ bool TCompiler::checkCallDepth()
if (depth >= maxCallStackDepth)
{
// Trace back the function chain to have a meaningful info log.
infoSink.info.prefix(EPrefixError);
infoSink.info << "Call stack too deep (larger than " << maxCallStackDepth
<< ") with the following call chain: " << record.name;
std::stringstream errorStream;
errorStream << "Call stack too deep (larger than " << maxCallStackDepth
<< ") with the following call chain: " << record.name;
int currentFunction = static_cast<int>(i);
int currentDepth = depth;
while (currentFunction != -1)
{
infoSink.info << " -> " << mCallDag.getRecordFromIndex(currentFunction).name;
errorStream << " -> " << mCallDag.getRecordFromIndex(currentFunction).name;
int nextFunction = -1;
for (auto &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
......@@ -724,6 +720,9 @@ bool TCompiler::checkCallDepth()
currentFunction = nextFunction;
}
std::string errorStr = errorStream.str();
mDiagnostics.globalError(errorStr.c_str());
return false;
}
}
......@@ -743,8 +742,7 @@ bool TCompiler::tagUsedFunctions()
}
}
infoSink.info.prefix(EPrefixError);
infoSink.info << "Missing main()\n";
mDiagnostics.globalError("Missing main()");
return false;
}
......@@ -830,14 +828,15 @@ bool TCompiler::validateOutputs(TIntermNode *root)
{
ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers);
root->traverse(&validateOutputs);
return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
validateOutputs.validate(&mDiagnostics);
return (mDiagnostics.numErrors() == 0);
}
bool TCompiler::validateLimitations(TIntermNode *root)
{
ValidateLimitations validate(shaderType, &infoSink.info);
ValidateLimitations validate(shaderType, &mDiagnostics);
root->traverse(&validate);
return validate.numErrors() == 0;
return mDiagnostics.numErrors() == 0;
}
bool TCompiler::limitExpressionComplexity(TIntermNode *root)
......@@ -847,13 +846,13 @@ bool TCompiler::limitExpressionComplexity(TIntermNode *root)
if (traverser.getMaxDepth() > maxExpressionComplexity)
{
infoSink.info << "Expression too complex.";
mDiagnostics.globalError("Expression too complex.");
return false;
}
if (!ValidateMaxParameters::validate(root, maxFunctionParameters))
{
infoSink.info << "Function has too many parameters.";
mDiagnostics.globalError("Function has too many parameters.");
return false;
}
......
......@@ -16,6 +16,7 @@
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/CallDAG.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/InfoSink.h"
......@@ -239,6 +240,7 @@ class TCompiler : public TShHandleBase
// Results of compilation.
int shaderVersion;
TInfoSink infoSink; // Output sink.
TDiagnostics mDiagnostics;
const char *mSourcePath; // Path of source file or NULL
// compute shader local group size
......
......@@ -14,7 +14,7 @@
namespace sh
{
TDiagnostics::TDiagnostics(TInfoSink &infoSink)
TDiagnostics::TDiagnostics(TInfoSinkBase &infoSink)
: mInfoSink(infoSink), mNumErrors(0), mNumWarnings(0)
{
}
......@@ -25,30 +25,43 @@ TDiagnostics::~TDiagnostics()
void TDiagnostics::writeInfo(Severity severity,
const pp::SourceLocation &loc,
const std::string &reason,
const std::string &token)
const char *reason,
const char *token)
{
TPrefixType prefix = EPrefixNone;
switch (severity)
{
case PP_ERROR:
case SH_ERROR:
++mNumErrors;
prefix = EPrefixError;
break;
case PP_WARNING:
case SH_WARNING:
++mNumWarnings;
prefix = EPrefixWarning;
break;
default:
UNREACHABLE();
break;
}
TInfoSinkBase &sink = mInfoSink.info;
/* VC++ format: file(linenum) : error #: 'token' : extrainfo */
sink.prefix(prefix);
sink.location(loc.file, loc.line);
sink << "'" << token << "' : " << reason << "\n";
mInfoSink.prefix(severity);
mInfoSink.location(loc.file, loc.line);
mInfoSink << "'" << token << "' : " << reason << "\n";
}
void TDiagnostics::globalError(const char *message)
{
++mNumErrors;
mInfoSink.prefix(SH_ERROR);
mInfoSink << message << "\n";
}
void TDiagnostics::error(const pp::SourceLocation &loc, const char *reason, const char *token)
{
writeInfo(SH_ERROR, loc, reason, token);
}
void TDiagnostics::warning(const pp::SourceLocation &loc, const char *reason, const char *token)
{
writeInfo(SH_WARNING, loc, reason, token);
}
void TDiagnostics::error(const TSourceLoc &loc, const char *reason, const char *token)
......@@ -56,7 +69,7 @@ void TDiagnostics::error(const TSourceLoc &loc, const char *reason, const char *
pp::SourceLocation srcLoc;
srcLoc.file = loc.first_file;
srcLoc.line = loc.first_line;
writeInfo(pp::Diagnostics::PP_ERROR, srcLoc, reason, token);
error(srcLoc, reason, token);
}
void TDiagnostics::warning(const TSourceLoc &loc, const char *reason, const char *token)
......@@ -64,12 +77,18 @@ void TDiagnostics::warning(const TSourceLoc &loc, const char *reason, const char
pp::SourceLocation srcLoc;
srcLoc.file = loc.first_file;
srcLoc.line = loc.first_line;
writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token);
warning(srcLoc, reason, token);
}
void TDiagnostics::print(ID id, const pp::SourceLocation &loc, const std::string &text)
{
writeInfo(severity(id), loc, message(id), text);
writeInfo(isError(id) ? SH_ERROR : SH_WARNING, loc, message(id), text.c_str());
}
void TDiagnostics::resetErrorCount()
{
mNumErrors = 0;
mNumWarnings = 0;
}
} // namespace sh
......@@ -9,37 +9,43 @@
#include "common/angleutils.h"
#include "compiler/preprocessor/DiagnosticsBase.h"
#include "compiler/translator/Severity.h"
namespace sh
{
class TInfoSink;
class TInfoSinkBase;
struct TSourceLoc;
class TDiagnostics : public pp::Diagnostics, angle::NonCopyable
{
public:
TDiagnostics(TInfoSink &infoSink);
TDiagnostics(TInfoSinkBase &infoSink);
~TDiagnostics() override;
TInfoSink &infoSink() { return mInfoSink; }
int numErrors() const { return mNumErrors; }
int numWarnings() const { return mNumWarnings; }
void writeInfo(Severity severity,
const pp::SourceLocation &loc,
const std::string &reason,
const std::string &token);
void error(const pp::SourceLocation &loc, const char *reason, const char *token);
void warning(const pp::SourceLocation &loc, const char *reason, const char *token);
void error(const TSourceLoc &loc, const char *reason, const char *token);
void warning(const TSourceLoc &loc, const char *reason, const char *token);
void globalError(const char *message);
void resetErrorCount();
protected:
void writeInfo(Severity severity,
const pp::SourceLocation &loc,
const char *reason,
const char *token);
void print(ID id, const pp::SourceLocation &loc, const std::string &text) override;
private:
TInfoSink &mInfoSink;
TInfoSinkBase &mInfoSink;
int mNumErrors;
int mNumWarnings;
};
......
......@@ -52,7 +52,7 @@ TDirectiveHandler::~TDirectiveHandler()
void TDirectiveHandler::handleError(const pp::SourceLocation &loc, const std::string &msg)
{
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, msg, "");
mDiagnostics.error(loc, msg.c_str(), "");
}
void TDirectiveHandler::handlePragma(const pp::SourceLocation &loc,
......@@ -70,9 +70,9 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation &loc,
if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER)
{
// ESSL 3.00.4 section 4.6.1
mDiagnostics.writeInfo(
pp::Diagnostics::PP_ERROR, loc,
"#pragma STDGL invariant(all) can not be used in fragment shader", name);
mDiagnostics.error(
loc, "#pragma STDGL invariant(all) can not be used in fragment shader",
name.c_str());
}
mPragma.stdgl.invariantAll = true;
}
......@@ -125,8 +125,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation &loc,
if (invalidValue)
{
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
"invalid pragma value - 'on' or 'off' expected", value);
mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str());
}
}
}
......@@ -140,7 +139,7 @@ void TDirectiveHandler::handleExtension(const pp::SourceLocation &loc,
TBehavior behaviorVal = getBehavior(behavior);
if (behaviorVal == EBhUndefined)
{
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, "behavior invalid", name);
mDiagnostics.error(loc, "behavior invalid", name.c_str());
return;
}
......@@ -148,13 +147,11 @@ void TDirectiveHandler::handleExtension(const pp::SourceLocation &loc,
{
if (behaviorVal == EBhRequire)
{
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
"extension cannot have 'require' behavior", name);
mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str());
}
else if (behaviorVal == EBhEnable)
{
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
"extension cannot have 'enable' behavior", name);
mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str());
}
else
{
......@@ -172,22 +169,20 @@ void TDirectiveHandler::handleExtension(const pp::SourceLocation &loc,
return;
}
pp::Diagnostics::Severity severity = pp::Diagnostics::PP_ERROR;
switch (behaviorVal)
{
case EBhRequire:
severity = pp::Diagnostics::PP_ERROR;
mDiagnostics.error(loc, "extension is not supported", name.c_str());
break;
case EBhEnable:
case EBhWarn:
case EBhDisable:
severity = pp::Diagnostics::PP_WARNING;
mDiagnostics.warning(loc, "extension is not supported", name.c_str());
break;
default:
UNREACHABLE();
break;
}
mDiagnostics.writeInfo(severity, loc, "extension is not supported", name);
}
void TDirectiveHandler::handleVersion(const pp::SourceLocation &loc, int version)
......@@ -201,7 +196,7 @@ void TDirectiveHandler::handleVersion(const pp::SourceLocation &loc, int version
std::stringstream stream;
stream << version;
std::string str = stream.str();
mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, "version number not supported", str);
mDiagnostics.error(loc, "version number not supported", str.c_str());
}
}
......
......@@ -9,27 +9,16 @@
namespace sh
{
void TInfoSinkBase::prefix(TPrefixType p)
void TInfoSinkBase::prefix(Severity severity)
{
switch (p)
switch (severity)
{
case EPrefixNone:
break;
case EPrefixWarning:
case SH_WARNING:
sink.append("WARNING: ");
break;
case EPrefixError:
case SH_ERROR:
sink.append("ERROR: ");
break;
case EPrefixInternalError:
sink.append("INTERNAL ERROR: ");
break;
case EPrefixUnimplemented:
sink.append("UNIMPLEMENTED: ");
break;
case EPrefixNote:
sink.append("NOTE: ");
break;
default:
sink.append("UNKOWN ERROR: ");
break;
......@@ -48,17 +37,4 @@ void TInfoSinkBase::location(int file, int line)
sink.append(stream.str());
}
void TInfoSinkBase::location(const TSourceLoc &loc)
{
location(loc.first_file, loc.first_line);
}
void TInfoSinkBase::message(TPrefixType p, const TSourceLoc &loc, const char *m)
{
prefix(p);
location(loc);
sink.append(m);
sink.append("\n");
}
} // namespace sh
......@@ -10,6 +10,7 @@
#include <math.h>
#include <stdlib.h>
#include "compiler/translator/Common.h"
#include "compiler/translator/Severity.h"
namespace sh
{
......@@ -22,20 +23,6 @@ inline float fractionalPart(float f)
}
//
// TPrefixType is used to centralize how info log messages start.
// See below.
//
enum TPrefixType
{
EPrefixNone,
EPrefixWarning,
EPrefixError,
EPrefixInternalError,
EPrefixUnimplemented,
EPrefixNote
};
//
// Encapsulate info logs for all objects that have them.
//
// The methods are a general set of tools for getting a variety of
......@@ -113,10 +100,8 @@ class TInfoSinkBase
const TPersistString &str() const { return sink; }
const char *c_str() const { return sink.c_str(); }
void prefix(TPrefixType p);
void prefix(Severity severity);
void location(int file, int line);
void location(const TSourceLoc &loc);
void message(TPrefixType p, const TSourceLoc &loc, const char *m);
private:
TPersistString sink;
......
......@@ -176,7 +176,7 @@ void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
// Now that we are done changing the AST, do the analyses need for HLSL generation
CallDAG::InitResult success = mCallDag.init(treeRoot, &objSink);
CallDAG::InitResult success = mCallDag.init(treeRoot, nullptr);
ASSERT(success == CallDAG::INITDAG_SUCCESS);
mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag);
......
......@@ -74,7 +74,7 @@ TParseContext::TParseContext(TSymbolTable &symt,
ShShaderSpec spec,
ShCompileOptions options,
bool checksPrecErrors,
TInfoSink &is,
TDiagnostics *diagnostics,
const ShBuiltInResources &resources)
: intermediate(),
symbolTable(symt),
......@@ -93,13 +93,13 @@ TParseContext::TParseContext(TSymbolTable &symt,
mFragmentPrecisionHighOnESSL1(false),
mDefaultMatrixPacking(EmpColumnMajor),
mDefaultBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared),
mDiagnostics(is),
mDiagnostics(diagnostics),
mDirectiveHandler(ext,
mDiagnostics,
*mDiagnostics,
mShaderVersion,
mShaderType,
resources.WEBGL_debug_shader_precision == 1),
mPreprocessor(&mDiagnostics, &mDirectiveHandler, pp::PreprocessorSettings()),
mPreprocessor(mDiagnostics, &mDirectiveHandler, pp::PreprocessorSettings()),
mScanner(nullptr),
mUsesFragData(false),
mUsesFragColor(false),
......@@ -227,12 +227,12 @@ bool TParseContext::parseVectorFields(const TString &compString,
//
void TParseContext::error(const TSourceLoc &loc, const char *reason, const char *token)
{
mDiagnostics.error(loc, reason, token);
mDiagnostics->error(loc, reason, token);
}
void TParseContext::warning(const TSourceLoc &loc, const char *reason, const char *token)
{
mDiagnostics.warning(loc, reason, token);
mDiagnostics->warning(loc, reason, token);
}
void TParseContext::outOfRangeError(bool isError,
......@@ -1049,7 +1049,7 @@ void TParseContext::checkIsParameterQualifierValid(
const TTypeQualifierBuilder &typeQualifierBuilder,
TType *type)
{
TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(&mDiagnostics);
TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(mDiagnostics);
if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
{
......@@ -1688,7 +1688,7 @@ void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier)
TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
const TPublicType &typeSpecifier)
{
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
TPublicType returnType = typeSpecifier;
returnType.qualifier = typeQualifier.qualifier;
......@@ -2052,7 +2052,7 @@ TIntermInvariantDeclaration *TParseContext::parseInvariantDeclaration(
const TString *identifier,
const TSymbol *symbol)
{
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
if (!typeQualifier.invariant)
{
......@@ -2242,7 +2242,7 @@ void TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
{
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier,
......@@ -2627,7 +2627,7 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type,
{
// Array return values are forbidden, but there's also no valid syntax for declaring array
// return values in ESSL 1.00.
ASSERT(type.arraySize == 0 || mDiagnostics.numErrors() > 0);
ASSERT(type.arraySize == 0 || mDiagnostics->numErrors() > 0);
if (type.isStructureContainingArrays())
{
......@@ -2730,7 +2730,7 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
constructor->setType(type);
TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, &mDiagnostics);
TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, mDiagnostics);
if (constConstructor)
{
return constConstructor;
......@@ -2754,7 +2754,7 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
{
checkIsNotReserved(nameLine, blockName);
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
if (typeQualifier.qualifier != EvqUniform)
{
......@@ -3075,12 +3075,12 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
}
return intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location,
&mDiagnostics);
mDiagnostics);
}
else
{
return intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location,
&mDiagnostics);
mDiagnostics);
}
}
......@@ -3156,7 +3156,7 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
index->setLine(fieldLocation);
return intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index,
dotLocation, &mDiagnostics);
dotLocation, mDiagnostics);
}
else
{
......@@ -3190,7 +3190,7 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
index->setLine(fieldLocation);
return intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index,
dotLocation, &mDiagnostics);
dotLocation, mDiagnostics);
}
else
{
......@@ -3406,7 +3406,7 @@ TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualif
const TSourceLoc &rightQualifierLocation)
{
return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation,
&mDiagnostics);
mDiagnostics);
}
TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields,
......@@ -3432,7 +3432,7 @@ TFieldList *TParseContext::addStructDeclaratorListWithQualifiers(
TPublicType *typeSpecifier,
TFieldList *fieldList)
{
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
typeSpecifier->qualifier = typeQualifier.qualifier;
typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier;
......@@ -3563,7 +3563,7 @@ TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
if (statementList)
{
if (!ValidateSwitchStatementList(switchType, &mDiagnostics, statementList, loc))
if (!ValidateSwitchStatementList(switchType, mDiagnostics, statementList, loc))
{
return nullptr;
}
......@@ -3673,7 +3673,7 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op,
TIntermUnary *node = new TIntermUnary(op, child);
node->setLine(loc);
TIntermTyped *foldedNode = node->fold(&mDiagnostics);
TIntermTyped *foldedNode = node->fold(mDiagnostics);
if (foldedNode)
return foldedNode;
......@@ -4008,7 +4008,7 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
node->setLine(loc);
// See if we can fold constants.
TIntermTyped *foldedNode = node->fold(&mDiagnostics);
TIntermTyped *foldedNode = node->fold(mDiagnostics);
if (foldedNode)
return foldedNode;
......@@ -4408,7 +4408,7 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
// See if we can constant fold a built-in. Note that this may be possible even
// if it is not const-qualified.
TIntermTyped *foldedNode =
intermediate.foldAggregateBuiltIn(aggregate, &mDiagnostics);
intermediate.foldAggregateBuiltIn(aggregate, mDiagnostics);
if (foldedNode)
{
callNode = foldedNode;
......
......@@ -38,7 +38,7 @@ class TParseContext : angle::NonCopyable
ShShaderSpec spec,
ShCompileOptions options,
bool checksPrecErrors,
TInfoSink &is,
TDiagnostics *diagnostics,
const ShBuiltInResources &resources);
const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
......@@ -48,8 +48,7 @@ class TParseContext : angle::NonCopyable
int getShaderVersion() const { return mShaderVersion; }
sh::GLenum getShaderType() const { return mShaderType; }
ShShaderSpec getShaderSpec() const { return mShaderSpec; }
int numErrors() const { return mDiagnostics.numErrors(); }
TInfoSink &infoSink() { return mDiagnostics.infoSink(); }
int numErrors() const { return mDiagnostics->numErrors(); }
void error(const TSourceLoc &loc, const char *reason, const char *token);
void warning(const TSourceLoc &loc, const char *reason, const char *token);
......@@ -435,7 +434,7 @@ class TParseContext : angle::NonCopyable
TLayoutMatrixPacking mDefaultMatrixPacking;
TLayoutBlockStorage mDefaultBlockStorage;
TString mHashErrMsg;
TDiagnostics mDiagnostics;
TDiagnostics *mDiagnostics;
TDirectiveHandler mDirectiveHandler;
pp::Preprocessor mPreprocessor;
void *mScanner;
......
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_SEVERITY_H_
#define COMPILER_TRANSLATOR_SEVERITY_H_
namespace sh
{
// Severity is used to classify info log messages.
enum Severity
{
SH_WARNING,
SH_ERROR
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_SEVERITY_H_
......@@ -5,7 +5,8 @@
//
#include "compiler/translator/ValidateLimitations.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/ParseContext.h"
#include "angle_gl.h"
......@@ -66,35 +67,14 @@ class ValidateConstIndexExpr : public TIntermTraverser
} // namespace anonymous
ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink)
ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, TDiagnostics *diagnostics)
: TIntermTraverser(true, false, false),
mShaderType(shaderType),
mSink(sink),
mNumErrors(0),
mDiagnostics(diagnostics),
mValidateIndexing(true),
mValidateInnerLoops(true)
{
}
// static
bool ValidateLimitations::IsLimitedForLoop(TIntermLoop *loop)
{
// The shader type doesn't matter in this case.
ValidateLimitations validate(GL_FRAGMENT_SHADER, nullptr);
validate.mValidateIndexing = false;
validate.mValidateInnerLoops = false;
if (!validate.validateLoopType(loop))
return false;
if (!validate.validateForLoopHeader(loop))
return false;
TIntermNode *body = loop->getBody();
if (body != nullptr)
{
validate.mLoopSymbolIds.push_back(GetLoopSymbolId(loop));
body->traverse(&validate);
validate.mLoopSymbolIds.pop_back();
}
return (validate.mNumErrors == 0);
ASSERT(diagnostics);
}
bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node)
......@@ -162,13 +142,7 @@ bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node)
void ValidateLimitations::error(TSourceLoc loc, const char *reason, const char *token)
{
if (mSink)
{
mSink->prefix(EPrefixError);
mSink->location(loc);
(*mSink) << "'" << token << "' : " << reason << "\n";
}
++mNumErrors;
mDiagnostics->error(loc, reason, token);
}
bool ValidateLimitations::withinLoopBody() const
......
......@@ -12,24 +12,20 @@
namespace sh
{
class TInfoSinkBase;
class TDiagnostics;
// Traverses intermediate tree to ensure that the shader does not exceed the
// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
class ValidateLimitations : public TIntermTraverser
{
public:
ValidateLimitations(sh::GLenum shaderType, TInfoSinkBase *sink);
int numErrors() const { return mNumErrors; }
ValidateLimitations(sh::GLenum shaderType, TDiagnostics *diagnostics);
bool visitBinary(Visit, TIntermBinary *) override;
bool visitUnary(Visit, TIntermUnary *) override;
bool visitAggregate(Visit, TIntermAggregate *) override;
bool visitLoop(Visit, TIntermLoop *) override;
static bool IsLimitedForLoop(TIntermLoop *node);
private:
void error(TSourceLoc loc, const char *reason, const char *token);
......@@ -55,8 +51,7 @@ class ValidateLimitations : public TIntermTraverser
bool validateIndexing(TIntermBinary *node);
sh::GLenum mShaderType;
TInfoSinkBase *mSink;
int mNumErrors;
TDiagnostics *mDiagnostics;
std::vector<int> mLoopSymbolIds;
bool mValidateIndexing;
bool mValidateInnerLoops;
......
......@@ -14,12 +14,9 @@ namespace sh
namespace
{
void error(int *errorCount, TInfoSinkBase &sink, const TIntermSymbol &symbol, const char *reason)
void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
{
sink.prefix(EPrefixError);
sink.location(symbol.getLine());
sink << "'" << symbol.getSymbol() << "' : " << reason << "\n";
(*errorCount)++;
diagnostics->error(symbol.getLine(), reason, symbol.getSymbol().c_str());
}
} // namespace
......@@ -55,10 +52,10 @@ void ValidateOutputs::visitSymbol(TIntermSymbol *symbol)
}
}
int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const
void ValidateOutputs::validate(TDiagnostics *diagnostics) const
{
ASSERT(diagnostics);
OutputVector validOutputs(mMaxDrawBuffers);
int errorCount = 0;
for (const auto &symbol : mOutputs)
{
......@@ -78,7 +75,7 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const
std::stringstream strstr;
strstr << "conflicting output locations with previously defined output '"
<< validOutputs[offsetLocation]->getSymbol() << "'";
error(&errorCount, sink, *symbol, strstr.str().c_str());
error(*symbol, strstr.str().c_str(), diagnostics);
}
else
{
......@@ -90,9 +87,10 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const
{
if (elementCount > 0)
{
error(&errorCount, sink, *symbol,
error(*symbol,
elementCount > 1 ? "output array locations would exceed MAX_DRAW_BUFFERS"
: "output location must be < MAX_DRAW_BUFFERS");
: "output location must be < MAX_DRAW_BUFFERS",
diagnostics);
}
}
}
......@@ -103,11 +101,11 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const
{
for (const auto &symbol : mUnspecifiedLocationOutputs)
{
error(&errorCount, sink, *symbol,
"must explicitly specify all locations when using multiple fragment outputs");
error(*symbol,
"must explicitly specify all locations when using multiple fragment outputs",
diagnostics);
}
}
return errorCount;
}
} // namespace sh
......@@ -22,7 +22,7 @@ class ValidateOutputs : public TIntermTraverser
public:
ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers);
int validateAndCountErrors(TInfoSinkBase &sink) const;
void validate(TDiagnostics *diagnostics) const;
void visitSymbol(TIntermSymbol *) override;
......
......@@ -65,7 +65,7 @@ void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
{
int i;
sink.location(node->getLine());
sink.location(node->getLine().first_file, node->getLine().first_line);
for (i = 0; i < depth; ++i)
sink << " ";
......@@ -476,7 +476,7 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
break;
default:
out.prefix(EPrefixError);
out.prefix(SH_ERROR);
out << "Bad unary op";
}
......@@ -512,7 +512,7 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
if (node->getOp() == EOpNull)
{
out.prefix(EPrefixError);
out.prefix(SH_ERROR);
out << "node is still EOpNull!\n";
return true;
}
......@@ -687,7 +687,7 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
break;
default:
out.prefix(EPrefixError);
out.prefix(SH_ERROR);
out << "Bad aggregation op";
}
......@@ -853,7 +853,8 @@ void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
out << " (const uint)\n";
break;
default:
out.message(EPrefixInternalError, node->getLine(), "Unknown constant");
out.prefix(SH_ERROR);
out << "Unknown constant";
break;
}
}
......
......@@ -203,7 +203,7 @@ const char* ExpressionLimitTest::kExpressionTooComplex =
const char* ExpressionLimitTest::kCallStackTooDeep =
"Call stack too deep";
const char* ExpressionLimitTest::kHasRecursion =
"Function recursion detected";
"Recursive function call in the following call chain";
const char* ExpressionLimitTest::kTooManyParameters =
"Function has too many parameters";
......
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