summaryrefslogtreecommitdiff
path: root/cpp/src/Slice/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Slice/Parser.cpp')
-rw-r--r--cpp/src/Slice/Parser.cpp579
1 files changed, 418 insertions, 161 deletions
diff --git a/cpp/src/Slice/Parser.cpp b/cpp/src/Slice/Parser.cpp
index 8ee39d6e8bb..e1a88c3f559 100644
--- a/cpp/src/Slice/Parser.cpp
+++ b/cpp/src/Slice/Parser.cpp
@@ -63,6 +63,56 @@ filterOrderedOptionalDataMembers(const DataMemberList& members)
return result;
}
+void
+sortOptionalParameters(ParamDeclList& params)
+{
+ //
+ // Sort optional parameters by tag.
+ //
+ class SortFn
+ {
+ public:
+ static bool compare(const ParamDeclPtr& lhs, const ParamDeclPtr& rhs)
+ {
+ return lhs->tag() < rhs->tag();
+ }
+ };
+ params.sort(SortFn::compare);
+}
+
+bool
+isMutableAfterReturnType(const TypePtr& type)
+{
+ //
+ // Returns true if the type contains data types which can be referenced by user code
+ // and mutated after a dispatch returns.
+ //
+
+ if(ClassDeclPtr::dynamicCast(type))
+ {
+ return true;
+ }
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin && (builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue))
+ {
+ return true;
+ }
+
+ if(SequencePtr::dynamicCast(type) || DictionaryPtr::dynamicCast(type))
+ {
+ return true;
+ }
+
+ StructPtr s = StructPtr::dynamicCast(type);
+ if(s)
+ {
+ return true;
+ }
+
+ return false;
+}
+
}
namespace Slice
@@ -258,6 +308,11 @@ Slice::Builtin::typeId() const
return "::Ice::LocalObject";
break;
}
+ case KindValue:
+ {
+ return "::Ice::Value";
+ break;
+ }
}
assert(false);
return ""; // Keep the compiler happy.
@@ -266,7 +321,7 @@ Slice::Builtin::typeId() const
bool
Slice::Builtin::usesClasses() const
{
- return _kind == KindObject;
+ return _kind == KindObject || _kind == KindValue;
}
size_t
@@ -283,7 +338,8 @@ Slice::Builtin::minWireSize() const
8, // KindDouble
1, // KindString: at least one byte for an empty string.
1, // KindObject: at least one byte (to marshal an index instead of an instance).
- 2 // KindObjectProxy: at least an empty identity for a nil proxy, that is, 2 bytes.
+ 2, // KindObjectProxy: at least an empty identity for a nil proxy, that is, 2 bytes.
+ 1 // KindValue: at least one byte (to marshal an index instead of an instance).
};
assert(_kind != KindLocalObject);
@@ -293,7 +349,7 @@ Slice::Builtin::minWireSize() const
bool
Slice::Builtin::isVariableLength() const
{
- return _kind == KindString || _kind == KindObject || _kind == KindObjectProxy;
+ return _kind == KindString || _kind == KindObject || _kind == KindObjectProxy || _kind == KindValue;
}
Builtin::Kind
@@ -320,7 +376,8 @@ const char* Slice::Builtin::builtinTable[] =
"string",
"Object",
"Object*",
- "LocalObject"
+ "LocalObject",
+ "Value"
};
Slice::Builtin::Builtin(const UnitPtr& unit, Kind kind) :
@@ -496,12 +553,6 @@ Slice::Contained::operator==(const Contained& rhs) const
return _scoped == rhs._scoped;
}
-bool
-Slice::Contained::operator!=(const Contained& rhs) const
-{
- return _scoped != rhs._scoped;
-}
-
Slice::Contained::Contained(const ContainerPtr& container, const string& name) :
SyntaxTreeBase(container->unit()),
_container(container),
@@ -876,17 +927,6 @@ Slice::Container::createSequence(const string& name, const TypePtr& type, const
{
checkIdentifier(name);
- if(_unit->profile() == IceE && !local)
- {
- BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
- if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(type))
- {
- string msg = "Sequence `" + name + "' cannot contain object values.";
- _unit->error(msg);
- return 0;
- }
- }
-
ContainedList matches = _unit->findContents(thisScope() + name);
if(!matches.empty())
{
@@ -942,17 +982,6 @@ Slice::Container::createDictionary(const string& name, const TypePtr& keyType, c
{
checkIdentifier(name);
- if(_unit->profile() == IceE && !local)
- {
- BuiltinPtr builtin = BuiltinPtr::dynamicCast(valueType);
- if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(valueType))
- {
- string msg = "Dictionary `" + name + "' cannot contain object values.";
- _unit->error(msg);
- return 0;
- }
- }
-
ContainedList matches = _unit->findContents(thisScope() + name);
if(!matches.empty())
{
@@ -1178,16 +1207,8 @@ Slice::Container::lookupType(const string& scoped, bool printError)
return lookupTypeNoBuiltin(scoped, printError);
}
-//
-// TODO: Hack to keep binary compatibility with Ice 3.6.0, fix properly in Ice 3.7
-//
-namespace
-{
-bool ignoreUndefined = false;
-}
-
TypeList
-Slice::Container::lookupTypeNoBuiltin(const string& scoped, bool printError)
+Slice::Container::lookupTypeNoBuiltin(const string& scoped, bool printError, bool ignoreUndefined)
{
//
// Remove whitespace.
@@ -1304,12 +1325,7 @@ Slice::Container::lookupTypeNoBuiltin(const string& scoped, bool printError)
ContainedPtr contained = ContainedPtr::dynamicCast(this);
if(contained)
{
- if(typeError)
- {
- ignoreUndefined = true;
- }
- results = contained->container()->lookupTypeNoBuiltin(sc, printError);
- ignoreUndefined = false;
+ results = contained->container()->lookupTypeNoBuiltin(sc, printError, typeError || ignoreUndefined);
}
else if(!typeError)
{
@@ -1610,7 +1626,7 @@ Slice::Container::hasLocalClassDefsWithAsync() const
ClassDefPtr cl = ClassDefPtr::dynamicCast(*p);
if(cl && cl->isLocal())
{
- if(cl->hasMetaData("async"))
+ if(cl->hasMetaData("async-oneway"))
{
return true;
}
@@ -1618,7 +1634,7 @@ Slice::Container::hasLocalClassDefsWithAsync() const
OperationList ol = cl->operations();
for(OperationList::const_iterator q = ol.begin(); q != ol.end(); ++q)
{
- if((*q)->hasMetaData("async"))
+ if((*q)->hasMetaData("async-oneway"))
{
return true;
}
@@ -1677,7 +1693,47 @@ Slice::Container::hasNonLocalExceptions() const
return false;
}
+bool
+Slice::Container::hasStructs() const
+{
+ for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+ {
+ StructPtr q = StructPtr::dynamicCast(*p);
+ if(q)
+ {
+ return true;
+ }
+
+ ContainerPtr container = ContainerPtr::dynamicCast(*p);
+ if(container && container->hasStructs())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Slice::Container::hasExceptions() const
+{
+ for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+ {
+ ExceptionPtr q = ExceptionPtr::dynamicCast(*p);
+ if(q)
+ {
+ return true;
+ }
+
+ ContainerPtr container = ContainerPtr::dynamicCast(*p);
+ if(container && container->hasExceptions())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
bool
Slice::Container::hasClassDecls() const
@@ -1775,6 +1831,66 @@ Slice::Container::hasClassDefs() const
}
bool
+Slice::Container::hasLocalClassDefs() const
+{
+ for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+ {
+ ClassDefPtr cl = ClassDefPtr::dynamicCast(*p);
+ if(cl && cl->isLocal())
+ {
+ return true;
+ }
+
+ ContainerPtr container = ContainerPtr::dynamicCast(*p);
+ if(container && container->hasLocalClassDefs())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Slice::Container::hasNonLocalInterfaceDefs() const
+{
+ for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+ {
+ ClassDefPtr cl = ClassDefPtr::dynamicCast(*p);
+ if(cl && !cl->isLocal() && (cl->isInterface() || !cl->allOperations().empty()))
+ {
+ return true;
+ }
+
+ ContainerPtr container = ContainerPtr::dynamicCast(*p);
+ if(container && container->hasNonLocalInterfaceDefs())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Slice::Container::hasValueDefs() const
+{
+ for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+ {
+ ClassDefPtr cl = ClassDefPtr::dynamicCast(*p);
+ if(cl && !cl->isLocal() && !cl->isInterface())
+ {
+ return true;
+ }
+
+ ContainerPtr container = ContainerPtr::dynamicCast(*p);
+ if(container && container->hasValueDefs())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
Slice::Container::hasOnlyClassDecls() const
{
for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
@@ -2575,6 +2691,7 @@ Slice::Container::validateConstant(const string& name, const TypePtr& type, cons
case Builtin::KindObject:
case Builtin::KindObjectProxy:
case Builtin::KindLocalObject:
+ case Builtin::KindValue:
{
assert(false);
break;
@@ -3199,28 +3316,6 @@ Slice::ClassDef::createDataMember(const string& name, const TypePtr& type, bool
{
checkIdentifier(name);
- if(_unit->profile() == IceE)
- {
- if(!isLocal())
- {
- BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
- if((builtin && builtin->kind() == Builtin::KindObject))
- {
- string msg = "Class data member `" + name + "' cannot be a value object.";
- _unit->error(msg);
- return 0;
- }
-
- ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type);
- if(classDecl != 0 && !classDecl->isLocal())
- {
- string msg = "Class data member `" + name + "' cannot be a value object.";
- _unit->error(msg);
- return 0;
- }
- }
- }
-
assert(!isInterface());
ContainedList matches = _unit->findContents(thisScope() + name);
if(!matches.empty())
@@ -3456,7 +3551,9 @@ Slice::ClassDef::classDataMembers() const
if(q)
{
BuiltinPtr builtin = BuiltinPtr::dynamicCast(q->type());
- if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(q->type()))
+ if((builtin && builtin->kind() == Builtin::KindObject) ||
+ (builtin && builtin->kind() == Builtin::KindValue) ||
+ ClassDeclPtr::dynamicCast(q->type()))
{
result.push_back(q);
}
@@ -3603,6 +3700,17 @@ Slice::ClassDef::inheritsMetaData(const string& meta) const
return false;
}
+bool
+Slice::ClassDef::hasBaseDataMembers() const
+{
+ if(!_bases.empty() && !_bases.front()->isInterface())
+ {
+ return !_bases.front()->allDataMembers().empty();
+ }
+
+ return false;
+}
+
Contained::ContainedType
Slice::ClassDef::containedType() const
{
@@ -3645,6 +3753,11 @@ Slice::ClassDef::compactId() const
return _compactId;
}
+bool
+Slice::ClassDef::isDelegate() const
+{
+ return isLocal() && isInterface() && hasMetaData("delegate") && allOperations().size() == 1;
+}
Slice::ClassDef::ClassDef(const ContainerPtr& container, const string& name, int id, bool intf, const ClassList& bases,
bool local) :
SyntaxTreeBase(container->unit()),
@@ -3739,28 +3852,6 @@ Slice::Exception::createDataMember(const string& name, const TypePtr& type, bool
{
checkIdentifier(name);
- if(_unit->profile() == IceE)
- {
- if(!isLocal())
- {
- BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
- if((builtin && builtin->kind() == Builtin::KindObject))
- {
- string msg = "Exception data member `" + name + "' cannot be a value object.";
- _unit->error(msg);
- return 0;
- }
-
- ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type);
- if(classDecl != 0 && !classDecl->isLocal())
- {
- string msg = "Exception data member `" + name + "' cannot be a value object.";
- _unit->error(msg);
- return 0;
- }
- }
- }
-
ContainedList matches = _unit->findContents(thisScope() + name);
if(!matches.empty())
{
@@ -3925,7 +4016,9 @@ Slice::Exception::classDataMembers() const
if(q)
{
BuiltinPtr builtin = BuiltinPtr::dynamicCast(q->type());
- if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(q->type()))
+ if((builtin && builtin->kind() == Builtin::KindObject) ||
+ (builtin && builtin->kind() == Builtin::KindValue) ||
+ ClassDeclPtr::dynamicCast(q->type()))
{
result.push_back(q);
}
@@ -4059,6 +4152,12 @@ Slice::Exception::inheritsMetaData(const string& meta) const
return false;
}
+bool
+Slice::Exception::hasBaseDataMembers() const
+{
+ return _base && !_base->allDataMembers().empty();
+}
+
string
Slice::Exception::kindOf() const
{
@@ -4093,29 +4192,6 @@ Slice::Struct::createDataMember(const string& name, const TypePtr& type, bool op
const SyntaxTreeBasePtr& defaultValueType, const string& defaultValue,
const string& defaultLiteral)
{
- checkIdentifier(name);
-
- if(_unit->profile() == IceE)
- {
- if(!isLocal())
- {
- BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
- if((builtin && builtin->kind() == Builtin::KindObject))
- {
- string msg = "Struct data member `" + name + "' cannot be a value object.";
- _unit->error(msg);
- return 0;
- }
- ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type);
- if(classDecl != 0 && !classDecl->isLocal())
- {
- string msg = "Struct data member `" + name + "' cannot be a value object.";
- _unit->error(msg);
- return 0;
- }
- }
- }
-
ContainedList matches = _unit->findContents(thisScope() + name);
if(!matches.empty())
{
@@ -4230,7 +4306,9 @@ Slice::Struct::classDataMembers() const
if(q)
{
BuiltinPtr builtin = BuiltinPtr::dynamicCast(q->type());
- if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(q->type()))
+ if((builtin && builtin->kind() == Builtin::KindObject) ||
+ (builtin && builtin->kind() == Builtin::KindValue) ||
+ ClassDeclPtr::dynamicCast(q->type()))
{
result.push_back(q);
}
@@ -4569,6 +4647,7 @@ Slice::Dictionary::legalKeyType(const TypePtr& type, bool& containsSequence)
case Builtin::KindObject:
case Builtin::KindObjectProxy:
case Builtin::KindLocalObject:
+ case Builtin::KindValue:
{
return false;
break;
@@ -4941,33 +5020,33 @@ Slice::Operation::sendMode() const
}
}
-ParamDeclPtr
-Slice::Operation::createParamDecl(const string& name, const TypePtr& type, bool isOutParam, bool optional, int tag)
+bool
+Slice::Operation::hasMarshaledResult() const
{
- checkIdentifier(name);
-
- if(_unit->profile() == IceE)
+ ClassDefPtr cl = ClassDefPtr::dynamicCast(container());
+ assert(cl);
+ if(cl->hasMetaData("marshaled-result") || hasMetaData("marshaled-result"))
{
- ClassDefPtr cl = ClassDefPtr::dynamicCast(this->container());
- assert(cl);
- if(!cl->isLocal())
+ if(returnType() && isMutableAfterReturnType(returnType()))
{
- BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
- if((builtin && builtin->kind() == Builtin::KindObject))
- {
- string msg = "Object `" + name + "' cannot be passed by value.";
- _unit->error(msg);
- return 0;
- }
- ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type);
- if(classDecl != 0 && !classDecl->isLocal())
+ return true;
+ }
+ for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+ {
+ ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p);
+ if(q->isOutParam() && isMutableAfterReturnType(q->type()))
{
- string msg = "Object `" + name + "' cannot be passed by value.";
- _unit->error(msg);
- return 0;
+ return true;
}
}
}
+ return false;
+}
+
+ParamDeclPtr
+Slice::Operation::createParamDecl(const string& name, const TypePtr& type, bool isOutParam, bool optional, int tag)
+{
+ checkIdentifier(name);
ContainedList matches = _unit->findContents(thisScope() + name);
if(!matches.empty())
@@ -5067,6 +5146,74 @@ Slice::Operation::parameters() const
return result;
}
+ParamDeclList
+Slice::Operation::inParameters() const
+{
+ ParamDeclList result;
+ for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+ {
+ ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p);
+ if(q && !q->isOutParam())
+ {
+ result.push_back(q);
+ }
+ }
+ return result;
+}
+
+void
+Slice::Operation::inParameters(ParamDeclList& required, ParamDeclList& optional) const
+{
+ const ParamDeclList params = inParameters();
+ for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli)
+ {
+ if((*pli)->optional())
+ {
+ optional.push_back(*pli);
+ }
+ else
+ {
+ required.push_back(*pli);
+ }
+ }
+
+ sortOptionalParameters(optional);
+}
+
+ParamDeclList
+Slice::Operation::outParameters() const
+{
+ ParamDeclList result;
+ for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p)
+ {
+ ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p);
+ if(q && q->isOutParam())
+ {
+ result.push_back(q);
+ }
+ }
+ return result;
+}
+
+void
+Slice::Operation::outParameters(ParamDeclList& required, ParamDeclList& optional) const
+{
+ const ParamDeclList params = outParameters();
+ for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli)
+ {
+ if((*pli)->optional())
+ {
+ optional.push_back(*pli);
+ }
+ else
+ {
+ required.push_back(*pli);
+ }
+ }
+
+ sortOptionalParameters(optional);
+}
+
ExceptionList
Slice::Operation::throws() const
{
@@ -5219,12 +5366,25 @@ Slice::Operation::returnsData() const
}
bool
+Slice::Operation::returnsMultipleValues() const
+{
+ size_t count = outParameters().size();
+
+ if(returnType())
+ {
+ ++count;
+ }
+
+ return count > 1;
+}
+
+bool
Slice::Operation::sendsOptionals() const
{
- ParamDeclList pdl = parameters();
+ ParamDeclList pdl = inParameters();
for(ParamDeclList::const_iterator i = pdl.begin(); i != pdl.end(); ++i)
{
- if(!(*i)->isOutParam() && (*i)->optional())
+ if((*i)->optional())
{
return true;
}
@@ -5356,26 +5516,6 @@ Slice::Operation::Operation(const ContainerPtr& container,
_returnTag(returnTag),
_mode(mode)
{
- if(_unit->profile() == IceE)
- {
- ClassDefPtr cl = ClassDefPtr::dynamicCast(this->container());
- assert(cl);
- if(!cl->isLocal())
- {
- BuiltinPtr builtin = BuiltinPtr::dynamicCast(returnType);
- if((builtin && builtin->kind() == Builtin::KindObject))
- {
- string msg = "Method `" + name + "' cannot return an object by value.";
- _unit->error(msg);
- }
- ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(returnType);
- if(classDecl != 0 && !classDecl->isLocal())
- {
- string msg = "Method `" + name + "' cannot return an object by value.";
- _unit->error(msg);
- }
- }
- }
}
// ----------------------------------------------------------------------
@@ -6038,6 +6178,11 @@ Slice::Unit::usesNonLocals() const
return true;
}
+ if(_builtins.find(Builtin::KindValue) != _builtins.end())
+ {
+ return true;
+ }
+
return false;
}
@@ -6130,6 +6275,11 @@ Slice::Unit::parse(const string& filename, FILE* file, bool debug, Slice::Featur
popContainer();
assert(_definitionContextStack.size() == 1);
popDefinitionContext();
+
+ if(!checkUndefinedTypes())
+ {
+ status = EXIT_FAILURE;
+ }
}
Slice::unit = 0;
@@ -6228,6 +6378,113 @@ Slice::Unit::eraseWhiteSpace(string& s)
}
}
+bool
+Slice::Unit::checkUndefinedTypes()
+{
+ class Visitor : public ParserVisitor
+ {
+ public:
+
+ Visitor(int& errors) :
+ _errors(errors),
+ _local(false)
+ {
+ }
+
+ virtual bool visitClassDefStart(const ClassDefPtr& p)
+ {
+ _local = p->isLocal();
+ return true;
+ }
+
+ virtual bool visitExceptionStart(const ExceptionPtr& p)
+ {
+ _local = p->isLocal();
+ return true;
+ }
+
+ virtual bool visitStructStart(const StructPtr& p)
+ {
+ _local = p->isLocal();
+ return true;
+ }
+
+ virtual void visitOperation(const OperationPtr& p)
+ {
+ if(p->returnType())
+ {
+ checkUndefined(p->returnType(), "return type", p->file(), p->line());
+ }
+ ParamDeclList params = p->parameters();
+ for(ParamDeclList::const_iterator q = params.begin(); q != params.end(); ++q)
+ {
+ checkUndefined((*q)->type(), "parameter " + (*q)->name(), (*q)->file(), (*q)->line());
+ }
+ }
+
+ virtual void visitParamDecl(const ParamDeclPtr& p)
+ {
+ checkUndefined(p->type(), "parameter " + p->name(), p->file(), p->line());
+ }
+
+ virtual void visitDataMember(const DataMemberPtr& p)
+ {
+ checkUndefined(p->type(), "member " + p->name(), p->file(), p->line());
+ }
+
+ virtual void visitSequence(const SequencePtr& p)
+ {
+ _local = p->isLocal();
+ checkUndefined(p->type(), "element type", p->file(), p->line());
+ }
+
+ virtual void visitDictionary(const DictionaryPtr& p)
+ {
+ _local = p->isLocal();
+ checkUndefined(p->keyType(), "key type", p->file(), p->line());
+ checkUndefined(p->valueType(), "value type", p->file(), p->line());
+ }
+
+ private:
+
+ void checkUndefined(const TypePtr& type, const string& desc, const string& file, const string& line)
+ {
+ //
+ // See ICE-6867. Any use of a proxy requires the full type definition, as does any
+ // use of a class in a non-local context.
+ //
+ ProxyPtr p = ProxyPtr::dynamicCast(type);
+ if(p)
+ {
+ const ClassDeclPtr cl = p->_class();
+ if(!cl->definition())
+ {
+ ostringstream ostr;
+ ostr << desc << " uses a proxy for undefined type `" << cl->scoped() << "'";
+ emitError(file, line, ostr.str());
+ _errors++;
+ }
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl && !cl->definition() && !_local)
+ {
+ ostringstream ostr;
+ ostr << desc << " refers to undefined type `" << cl->scoped() << "'";
+ emitError(file, line, ostr.str());
+ _errors++;
+ }
+ }
+
+ int& _errors;
+ bool _local;
+ };
+
+ Visitor v(_errors);
+ visit(&v, true);
+ return _errors == 0;
+}
+
// ----------------------------------------------------------------------
// CICompare
// ----------------------------------------------------------------------