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:
Matt Pharr
2012-04-12 17:28:30 -07:00
parent d88dbf3612
commit 5ece6fec04
15 changed files with 396 additions and 423 deletions

View File

@@ -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);
}