C++: Type deduction for auto-declared variables implemented

Handled to major cases of 'auto' variable declaration:
1. auto var = someInitializer;
2. Q_FOREACH(auto item, collection) or foreach(auto item, collection)

In first case type deducted directly from initializer. If variable has no initializer then corresponded error reported. In second case type deducted from '*collection.begin()' expression.

Change-Id: Ie930add1648b99440281ae04d973fd6904bc9e46
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
Flex Ferrum
2012-01-28 22:58:08 +04:00
committed by Roberto Raggi
parent 0651e28d04
commit c6fc0be8ae
5 changed files with 153 additions and 8 deletions

View File

@@ -337,8 +337,14 @@ FullySpecifiedType Bind::declarator(DeclaratorAST *ast, const FullySpecifiedType
return type;
std::swap(_declaratorId, declaratorId);
bool isAuto = false;
if (translationUnit()->cxx0xEnabled())
isAuto = type.isAuto();
for (SpecifierListAST *it = ast->attribute_list; it; it = it->next) {
type = this->specifier(it->value, type);
if (type.isAuto())
isAuto = true;
}
for (PtrOperatorListAST *it = ast->ptr_operator_list; it; it = it->next) {
type = this->ptrOperator(it->value, type);
@@ -349,9 +355,17 @@ FullySpecifiedType Bind::declarator(DeclaratorAST *ast, const FullySpecifiedType
type = this->coreDeclarator(ast->core_declarator, type);
for (SpecifierListAST *it = ast->post_attribute_list; it; it = it->next) {
type = this->specifier(it->value, type);
if (type.isAuto())
isAuto = true;
}
// unsigned equals_token = ast->equals_token;
ExpressionTy initializer = this->expression(ast->initializer);
if (translationUnit()->cxx0xEnabled() && isAuto) {
type = initializer;
type.setAuto(true);
}
std::swap(_declaratorId, declaratorId);
return type;
}
@@ -1231,11 +1245,29 @@ bool Bind::visit(ForeachStatementAST *ast)
}
DeclaratorIdAST *declaratorId = 0;
type = this->declarator(ast->declarator, type, &declaratorId);
const StringLiteral *initializer = 0;
if (type.isAuto() && translationUnit()->cxx0xEnabled()) {
ExpressionTy exprType = this->expression(ast->expression);
ArrayType* arrayType = 0;
arrayType = exprType->asArrayType();
if (arrayType != 0)
type = arrayType->elementType();
else if (ast->expression != 0) {
unsigned startOfExpression = ast->expression->firstToken();
unsigned endOfExpression = ast->expression->lastToken();
const StringLiteral *sl = asStringLiteral(startOfExpression, endOfExpression);
const std::string buff = std::string("*") + sl->chars() + ".begin()";
initializer = control()->stringLiteral(buff.c_str(), buff.size());
}
}
if (declaratorId && declaratorId->name) {
unsigned sourceLocation = location(declaratorId->name, ast->firstToken());
Declaration *decl = control()->newDeclaration(sourceLocation, declaratorId->name->name);
decl->setType(type);
decl->setInitializer(initializer);
block->addMember(decl);
}
@@ -1791,6 +1823,16 @@ bool Bind::visit(SimpleDeclarationAST *ast)
if (declaratorId && declaratorId->name)
fun->setName(declaratorId->name->name); // update the function name
}
else if (declTy.isAuto()) {
const ExpressionAST *initializer = it->value->initializer;
if (!initializer)
translationUnit()->error(location(declaratorId->name, ast->firstToken()), "auto-initialized variable must have an initializer");
else {
unsigned startOfExpression = initializer->firstToken();
unsigned endOfExpression = initializer->lastToken();
decl->setInitializer(asStringLiteral(startOfExpression, endOfExpression));
}
}
if (_scope->isClass()) {
decl->setVisibility(_visibility);
@@ -2576,8 +2618,10 @@ bool Bind::visit(SimpleSpecifierAST *ast)
break;
case T_AUTO:
if (_type.isAuto())
translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token));
if (!translationUnit()->cxx0xEnabled()) {
if (_type.isAuto())
translationUnit()->error(ast->specifier_token, "duplicate `%s'", spell(ast->specifier_token));
}
_type.setAuto(true);
break;

View File

@@ -47,7 +47,6 @@ FullySpecifiedType FullySpecifiedType::qualifiedType() const
{
FullySpecifiedType ty = *this;
ty.setFriend(false);
ty.setAuto(false);
ty.setRegister(false);
ty.setStatic(false);
ty.setExtern(false);
@@ -236,4 +235,4 @@ bool FullySpecifiedType::match(const FullySpecifiedType &otherTy, TypeMatcher *m
return false;
return type()->matchType(otherTy.type(), matcher);
}
}

View File

@@ -92,11 +92,13 @@ void UsingDeclaration::visitSymbol0(SymbolVisitor *visitor)
Declaration::Declaration(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name)
: Symbol(translationUnit, sourceLocation, name)
, _initializer(0)
{ }
Declaration::Declaration(Clone *clone, Subst *subst, Declaration *original)
: Symbol(clone, subst, original)
, _type(clone->type(original->_type, subst))
, _initializer(clone->stringLiteral(original->_initializer))
{ }
Declaration::~Declaration()
@@ -105,9 +107,19 @@ Declaration::~Declaration()
void Declaration::setType(const FullySpecifiedType &type)
{ _type = type; }
void Declaration::setInitializer(const StringLiteral *initializer)
{
_initializer = initializer;
}
FullySpecifiedType Declaration::type() const
{ return _type; }
const StringLiteral *Declaration::getInitializer() const
{
return _initializer;
}
void Declaration::visitSymbol0(SymbolVisitor *visitor)
{ visitor->visit(this); }

View File

@@ -104,9 +104,11 @@ public:
virtual ~Declaration();
void setType(const FullySpecifiedType &type);
void setInitializer(StringLiteral const* initializer);
// Symbol's interface
virtual FullySpecifiedType type() const;
const StringLiteral *getInitializer() const;
virtual const Declaration *asDeclaration() const
{ return this; }
@@ -125,6 +127,7 @@ protected:
private:
FullySpecifiedType _type;
const StringLiteral *_initializer;
};
class CPLUSPLUS_EXPORT EnumeratorDeclaration: public Declaration