Substantial rewrite (again) of decl handling.
The decl.* code now no longer interacts with Symbols, but just returns names, types, initializer expressions, etc., as needed. This makes the code a bit more understandable. Fixes issues #171 and #130.
This commit is contained in:
172
module.cpp
172
module.cpp
@@ -231,64 +231,65 @@ Module::CompileFile() {
|
||||
|
||||
|
||||
void
|
||||
Module::AddTypeDef(Symbol *sym) {
|
||||
Module::AddTypeDef(const std::string &name, const Type *type,
|
||||
SourcePos pos) {
|
||||
// Typedefs are easy; just add the mapping between the given name and
|
||||
// the given type.
|
||||
symbolTable->AddType(sym->name.c_str(), sym->type, sym->pos);
|
||||
symbolTable->AddType(name.c_str(), type, pos);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
||||
Module::AddGlobalVariable(const std::string &name, const Type *type, Expr *initExpr,
|
||||
bool isConst, StorageClass storageClass, SourcePos pos) {
|
||||
// These may be NULL due to errors in parsing; just gracefully return
|
||||
// here if so.
|
||||
if (sym == NULL || sym->type == NULL) {
|
||||
// But if these are NULL and there haven't been any previous
|
||||
// errors, something surprising is going on
|
||||
if (name == "" || type == NULL) {
|
||||
Assert(errorCount > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (symbolTable->LookupFunction(sym->name.c_str())) {
|
||||
Error(sym->pos, "Global variable \"%s\" shadows previously-declared "
|
||||
"function.", sym->name.c_str());
|
||||
if (symbolTable->LookupFunction(name.c_str())) {
|
||||
Error(pos, "Global variable \"%s\" shadows previously-declared "
|
||||
"function.", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (sym->storageClass == SC_EXTERN_C) {
|
||||
Error(sym->pos, "extern \"C\" qualifier can only be used for "
|
||||
if (storageClass == SC_EXTERN_C) {
|
||||
Error(pos, "extern \"C\" qualifier can only be used for "
|
||||
"functions.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Type::Equal(sym->type, AtomicType::Void)) {
|
||||
Error(sym->pos, "\"void\" type global variable is illegal.");
|
||||
if (Type::Equal(type, AtomicType::Void)) {
|
||||
Error(pos, "\"void\" type global variable is illegal.");
|
||||
return;
|
||||
}
|
||||
|
||||
sym->type = ArrayType::SizeUnsizedArrays(sym->type, initExpr);
|
||||
if (sym->type == NULL)
|
||||
type = ArrayType::SizeUnsizedArrays(type, initExpr);
|
||||
if (type == NULL)
|
||||
return;
|
||||
|
||||
const ArrayType *at = dynamic_cast<const ArrayType *>(sym->type);
|
||||
const ArrayType *at = dynamic_cast<const ArrayType *>(type);
|
||||
if (at != NULL && at->TotalElementCount() == 0) {
|
||||
Error(sym->pos, "Illegal to declare a global variable with unsized "
|
||||
Error(pos, "Illegal to declare a global variable with unsized "
|
||||
"array dimensions that aren't set with an initializer "
|
||||
"expression.");
|
||||
return;
|
||||
}
|
||||
|
||||
LLVM_TYPE_CONST llvm::Type *llvmType = sym->type->LLVMType(g->ctx);
|
||||
LLVM_TYPE_CONST llvm::Type *llvmType = type->LLVMType(g->ctx);
|
||||
if (llvmType == NULL)
|
||||
return;
|
||||
|
||||
// See if we have an initializer expression for the global. If so,
|
||||
// make sure it's a compile-time constant!
|
||||
llvm::Constant *llvmInitializer = NULL;
|
||||
if (sym->storageClass == SC_EXTERN || sym->storageClass == SC_EXTERN_C) {
|
||||
ConstExpr *constValue = NULL;
|
||||
if (storageClass == SC_EXTERN || storageClass == SC_EXTERN_C) {
|
||||
if (initExpr != NULL)
|
||||
Error(sym->pos, "Initializer can't be provided with \"extern\" "
|
||||
"global variable \"%s\".", sym->name.c_str());
|
||||
Error(pos, "Initializer can't be provided with \"extern\" "
|
||||
"global variable \"%s\".", name.c_str());
|
||||
}
|
||||
else {
|
||||
if (initExpr != NULL) {
|
||||
@@ -299,27 +300,26 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
||||
// ExprList; they don't have types per se / can't type
|
||||
// convert themselves anyway.)
|
||||
if (dynamic_cast<ExprList *>(initExpr) == NULL)
|
||||
initExpr = TypeConvertExpr(initExpr, sym->type, "initializer");
|
||||
initExpr = TypeConvertExpr(initExpr, type, "initializer");
|
||||
|
||||
if (initExpr != NULL) {
|
||||
initExpr = Optimize(initExpr);
|
||||
// Fingers crossed, now let's see if we've got a
|
||||
// constant value..
|
||||
llvmInitializer = initExpr->GetConstant(sym->type);
|
||||
llvmInitializer = initExpr->GetConstant(type);
|
||||
|
||||
if (llvmInitializer != NULL) {
|
||||
if (sym->type->IsConstType())
|
||||
if (type->IsConstType())
|
||||
// Try to get a ConstExpr associated with
|
||||
// the symbol. This dynamic_cast can
|
||||
// validly fail, for example for types like
|
||||
// StructTypes where a ConstExpr can't
|
||||
// represent their values.
|
||||
sym->constValue =
|
||||
dynamic_cast<ConstExpr *>(initExpr);
|
||||
constValue = dynamic_cast<ConstExpr *>(initExpr);
|
||||
}
|
||||
else
|
||||
Error(initExpr->pos, "Initializer for global variable \"%s\" "
|
||||
"must be a constant.", sym->name.c_str());
|
||||
"must be a constant.", name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,30 +330,33 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
||||
llvmInitializer = llvm::Constant::getNullValue(llvmType);
|
||||
}
|
||||
|
||||
Symbol *stSym = symbolTable->LookupVariable(sym->name.c_str());
|
||||
Symbol *sym = symbolTable->LookupVariable(name.c_str());
|
||||
llvm::GlobalVariable *oldGV = NULL;
|
||||
if (stSym != NULL) {
|
||||
if (sym != NULL) {
|
||||
// We've already seen either a declaration or a definition of this
|
||||
// global.
|
||||
|
||||
// If the type doesn't match with the previous one, issue an error.
|
||||
if (!Type::Equal(sym->type, stSym->type)) {
|
||||
Error(sym->pos, "Definition of variable \"%s\" conflicts with "
|
||||
"definition at %s:%d.", sym->name.c_str(),
|
||||
stSym->pos.name, stSym->pos.first_line);
|
||||
if (!Type::Equal(sym->type, type) ||
|
||||
(sym->storageClass != SC_EXTERN &&
|
||||
sym->storageClass != SC_EXTERN_C &&
|
||||
sym->storageClass != storageClass)) {
|
||||
Error(pos, "Definition of variable \"%s\" conflicts with "
|
||||
"definition at %s:%d.", name.c_str(),
|
||||
sym->pos.name, sym->pos.first_line);
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::GlobalVariable *gv =
|
||||
llvm::dyn_cast<llvm::GlobalVariable>(stSym->storagePtr);
|
||||
llvm::dyn_cast<llvm::GlobalVariable>(sym->storagePtr);
|
||||
Assert(gv != NULL);
|
||||
|
||||
// And issue an error if this is a redefinition of a variable
|
||||
if (gv->hasInitializer() &&
|
||||
sym->storageClass != SC_EXTERN && sym->storageClass != SC_EXTERN_C) {
|
||||
Error(sym->pos, "Redefinition of variable \"%s\" is illegal. "
|
||||
Error(pos, "Redefinition of variable \"%s\" is illegal. "
|
||||
"(Previous definition at %s:%d.)", sym->name.c_str(),
|
||||
stSym->pos.name, stSym->pos.first_line);
|
||||
sym->pos.name, sym->pos.first_line);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -361,17 +364,12 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
||||
// of a previously-declared global. First, save the pointer to the
|
||||
// previous llvm::GlobalVariable
|
||||
oldGV = gv;
|
||||
|
||||
// Now copy over all of the members of the current Symbol to the
|
||||
// symbol in the symbol table.
|
||||
*stSym = *sym;
|
||||
// And copy the pointer of the one in the symbol table to sym, so
|
||||
// that the operations below update storagePtr for the Symbol
|
||||
// already in the symbol table.
|
||||
sym = stSym;
|
||||
}
|
||||
else
|
||||
else {
|
||||
sym = new Symbol(name, pos, type, storageClass);
|
||||
symbolTable->AddVariable(sym);
|
||||
}
|
||||
sym->constValue = constValue;
|
||||
|
||||
llvm::GlobalValue::LinkageTypes linkage =
|
||||
(sym->storageClass == SC_STATIC) ? llvm::GlobalValue::InternalLinkage :
|
||||
@@ -393,10 +391,10 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
||||
}
|
||||
|
||||
if (diBuilder) {
|
||||
llvm::DIFile file = sym->pos.GetDIFile();
|
||||
diBuilder->createGlobalVariable(sym->name,
|
||||
llvm::DIFile file = pos.GetDIFile();
|
||||
diBuilder->createGlobalVariable(name,
|
||||
file,
|
||||
sym->pos.first_line,
|
||||
pos.first_line,
|
||||
sym->type->GetDIType(file),
|
||||
(sym->storageClass == SC_STATIC),
|
||||
sym->storagePtr);
|
||||
@@ -487,22 +485,23 @@ lCheckForStructParameters(const FunctionType *ftype, SourcePos pos) {
|
||||
false if any errors were encountered.
|
||||
*/
|
||||
void
|
||||
Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
const FunctionType *functionType =
|
||||
dynamic_cast<const FunctionType *>(funSym->type);
|
||||
Module::AddFunctionDeclaration(const std::string &name,
|
||||
const FunctionType *functionType,
|
||||
StorageClass storageClass, bool isInline,
|
||||
SourcePos pos) {
|
||||
Assert(functionType != NULL);
|
||||
|
||||
// If a global variable with the same name has already been declared
|
||||
// issue an error.
|
||||
if (symbolTable->LookupVariable(funSym->name.c_str()) != NULL) {
|
||||
Error(funSym->pos, "Function \"%s\" shadows previously-declared global variable. "
|
||||
if (symbolTable->LookupVariable(name.c_str()) != NULL) {
|
||||
Error(pos, "Function \"%s\" shadows previously-declared global variable. "
|
||||
"Ignoring this definition.",
|
||||
funSym->name.c_str());
|
||||
name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Symbol *> overloadFuncs;
|
||||
symbolTable->LookupFunction(funSym->name.c_str(), &overloadFuncs);
|
||||
symbolTable->LookupFunction(name.c_str(), &overloadFuncs);
|
||||
if (overloadFuncs.size() > 0) {
|
||||
for (unsigned int i = 0; i < overloadFuncs.size(); ++i) {
|
||||
Symbol *overloadFunc = overloadFuncs[i];
|
||||
@@ -528,7 +527,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
if (i == functionType->GetNumParameters()) {
|
||||
std::string thisRetType = functionType->GetReturnTypeString();
|
||||
std::string otherRetType = ofType->GetReturnTypeString();
|
||||
Error(funSym->pos, "Illegal to overload function by return "
|
||||
Error(pos, "Illegal to overload function by return "
|
||||
"type only. This function returns \"%s\" while "
|
||||
"previous declaration at %s:%d returns \"%s\".",
|
||||
thisRetType.c_str(), overloadFunc->pos.name,
|
||||
@@ -539,55 +538,54 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
}
|
||||
}
|
||||
|
||||
if (funSym->storageClass == SC_EXTERN_C) {
|
||||
if (storageClass == SC_EXTERN_C) {
|
||||
// Make sure the user hasn't supplied both an 'extern "C"' and a
|
||||
// 'task' qualifier with the function
|
||||
if (functionType->isTask) {
|
||||
Error(funSym->pos, "\"task\" qualifier is illegal with C-linkage extern "
|
||||
"function \"%s\". Ignoring this function.", funSym->name.c_str());
|
||||
Error(pos, "\"task\" qualifier is illegal with C-linkage extern "
|
||||
"function \"%s\". Ignoring this function.", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Symbol *> funcs;
|
||||
symbolTable->LookupFunction(funSym->name.c_str(), &funcs);
|
||||
symbolTable->LookupFunction(name.c_str(), &funcs);
|
||||
if (funcs.size() > 0) {
|
||||
if (funcs.size() > 1) {
|
||||
// Multiple functions with this name have already been declared;
|
||||
// can't overload here
|
||||
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\"; "
|
||||
Error(pos, "Can't overload extern \"C\" function \"%s\"; "
|
||||
"%d functions with the same name have already been declared.",
|
||||
funSym->name.c_str(), (int)funcs.size());
|
||||
name.c_str(), (int)funcs.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// One function with the same name has been declared; see if it
|
||||
// has the same type as this one, in which case it's ok.
|
||||
if (Type::Equal(funcs[0]->type, funSym->type))
|
||||
if (Type::Equal(funcs[0]->type, functionType))
|
||||
return;
|
||||
else {
|
||||
Error(funSym->pos, "Can't overload extern \"C\" function \"%s\".",
|
||||
funSym->name.c_str());
|
||||
Error(pos, "Can't overload extern \"C\" function \"%s\".",
|
||||
name.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the LLVM FunctionType
|
||||
bool includeMask = (funSym->storageClass != SC_EXTERN_C);
|
||||
bool includeMask = (storageClass != SC_EXTERN_C);
|
||||
LLVM_TYPE_CONST llvm::FunctionType *llvmFunctionType =
|
||||
functionType->LLVMFunctionType(g->ctx, includeMask);
|
||||
if (llvmFunctionType == NULL)
|
||||
return;
|
||||
|
||||
// And create the llvm::Function
|
||||
llvm::GlobalValue::LinkageTypes linkage = (funSym->storageClass == SC_STATIC ||
|
||||
llvm::GlobalValue::LinkageTypes linkage = (storageClass == SC_STATIC ||
|
||||
isInline) ?
|
||||
llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::ExternalLinkage;
|
||||
std::string functionName;
|
||||
if (funSym->storageClass == SC_EXTERN_C)
|
||||
functionName = funSym->name;
|
||||
else {
|
||||
functionName = funSym->MangledName();
|
||||
|
||||
std::string functionName = name;
|
||||
if (storageClass != SC_EXTERN_C) {
|
||||
functionName += functionType->Mangle();
|
||||
if (g->mangleFunctionsWithTarget)
|
||||
functionName += g->target.GetISAString();
|
||||
}
|
||||
@@ -597,7 +595,7 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
|
||||
// Set function attributes: we never throw exceptions
|
||||
function->setDoesNotThrow(true);
|
||||
if (!(funSym->storageClass == SC_EXTERN_C) &&
|
||||
if (storageClass != SC_EXTERN_C &&
|
||||
!g->generateDebuggingSymbols &&
|
||||
isInline)
|
||||
function->addFnAttr(llvm::Attribute::AlwaysInline);
|
||||
@@ -609,15 +607,15 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
// 'export'ed.
|
||||
if (functionType->isExported &&
|
||||
lRecursiveCheckValidParamType(functionType->GetReturnType()))
|
||||
Error(funSym->pos, "Illegal to return a \"varying\" type from exported "
|
||||
"function \"%s\"", funSym->name.c_str());
|
||||
Error(pos, "Illegal to return a \"varying\" type from exported "
|
||||
"function \"%s\"", name.c_str());
|
||||
|
||||
if (functionType->isTask &&
|
||||
Type::Equal(functionType->GetReturnType(), AtomicType::Void) == false)
|
||||
Error(funSym->pos, "Task-qualified functions must have void return type.");
|
||||
Error(pos, "Task-qualified functions must have void return type.");
|
||||
|
||||
if (functionType->isExported || functionType->isExternC)
|
||||
lCheckForStructParameters(functionType, funSym->pos);
|
||||
lCheckForStructParameters(functionType, pos);
|
||||
|
||||
// Loop over all of the arguments; process default values if present
|
||||
// and do other checks and parameter attribute setting.
|
||||
@@ -675,19 +673,33 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) {
|
||||
function->eraseFromParent();
|
||||
function = module->getFunction(functionName);
|
||||
}
|
||||
funSym->function = function;
|
||||
|
||||
// Finally, we know all is good and we can add the function to the
|
||||
// symbol table
|
||||
Symbol *funSym = new Symbol(name, pos, functionType, storageClass);
|
||||
funSym->function = function;
|
||||
bool ok = symbolTable->AddFunction(funSym);
|
||||
Assert(ok);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Module::AddFunctionDefinition(Symbol *sym, const std::vector<Symbol *> &args,
|
||||
Module::AddFunctionDefinition(const std::string &name, const FunctionType *type,
|
||||
Stmt *code) {
|
||||
ast->AddFunction(sym, args, code);
|
||||
Symbol *sym = symbolTable->LookupFunction(name.c_str(), type);
|
||||
if (sym == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: because we encode the parameter names in the function type,
|
||||
// we need to override the function type here in case the function had
|
||||
// earlier been declared with anonymous parameter names but is now
|
||||
// defined with actual names. This is yet another reason we shouldn't
|
||||
// include the names in FunctionType...
|
||||
sym->type = type;
|
||||
|
||||
ast->AddFunction(sym, code);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user