VarDecl * NameResolver::HandleVarDecl(NameToken name, TypeSpecifier &spec, Expression *init) { Scope *scope = getOrCreateScope(); // :TODO: set variadic info VarDecl *var = new (pool_) VarDecl(name, init); // Note: the parser has already bound |var->init()| at this point, meaning // that aside from globals it should be impossible to self-initialize like: // int x = x; // // :TODO: do check this for globals. VariableSymbol *sym = new (pool_) VariableSymbol(var, scope, var->name()); registerSymbol(sym); var->setSymbol(sym); // Set this before we evaluate the type, since it determines whether or not // a const on a parameter is meaningless. if (spec.isByRef()) { assert(scope->kind() == Scope::Argument && sym->isArgument()); sym->storage_flags() |= StorageFlags::byref; } // See the comment in TypeResolver::visitVarDecl for why we do not want to // infer sizes from literals for arguments. if (init && !scope->isArgument() && ((init->isArrayLiteral() && init->asArrayLiteral()->isFixedArrayLiteral()) || (init->isStringLiteral()))) { // Wait until the type resolution pass to figure this out. We still have // to precompute the base though. if (Type *type = resolveBase(spec)) spec.setResolvedBaseType(type); var->te() = TypeExpr(new (pool_) TypeSpecifier(spec)); } else { VarDeclSpecHelper helper(var, nullptr); var->te() = resolve(spec, &helper); } if (var->te().resolved()) { sym->setType(var->te().resolved()); // We need to check this both here and in lazy resolution, which is gross, // but I don't see any obvious way to simplify it yet. if (spec.isByRef() && sym->type()->passesByReference()) { cc_.report(spec.byRefLoc(), rmsg::type_cannot_be_ref) << sym->type(); } } // Even if we were able to resolve the type, if we have to resolve a constant // value, we'll have to add it to the resolver queue. if (!var->te().resolved() || sym->canUseInConstExpr()) tr_.addPending(var); return var; }
bool VarDeclSpecHelper::receiveConstQualifier(CompileContext &cc, const SourceLocation &constLoc, Type *type) { VariableSymbol *sym = decl_->sym(); if (sym->isArgument()) { if (!!(sym->storage_flags() & StorageFlags::byref)) { cc.report(constLoc, rmsg::const_ref_has_no_meaning) << type; return true; } if (!type->passesByReference()) { cc.report(constLoc, rmsg::const_has_no_meaning) << type; return true; } } else if (TypeSupportsCompileTimeInterning(type)) { sym->storage_flags() |= StorageFlags::constval; } sym->storage_flags() |= StorageFlags::readonly; return true; }