diff --git a/decl.cpp b/decl.cpp index e17ed88c..c7d048c7 100644 --- a/decl.cpp +++ b/decl.cpp @@ -44,7 +44,7 @@ #include "stmt.h" #include "expr.h" #include -#include +#include /** Given a Type and a set of type qualifiers, apply the type qualifiers to the type, returning the type that is the result. @@ -112,13 +112,24 @@ DeclSpecs::GetBaseType(SourcePos pos) const { } +static const char * +lGetStorageClassName(StorageClass storageClass) { + switch (storageClass) { + case SC_NONE: return ""; + case SC_EXTERN: return "extern"; + case SC_EXTERN_C: return "extern \"C\""; + case SC_EXPORT: return "export"; + case SC_STATIC: return "static"; + case SC_TYPEDEF: return "typedef"; + default: FATAL("Unhandled storage class in lGetStorageClassName"); + return ""; + } +} + + void DeclSpecs::Print() const { - if (storageClass == SC_EXTERN) printf("extern "); - if (storageClass == SC_EXTERN_C) printf("extern \"C\" "); - if (storageClass == SC_EXPORT) printf("export "); - if (storageClass == SC_STATIC) printf("static "); - if (storageClass == SC_TYPEDEF) printf("typedef "); + printf("%s ", lGetStorageClassName(storageClass)); if (soaWidth > 0) printf("soa<%d> ", soaWidth); @@ -310,11 +321,17 @@ Declarator::GetType(const Type *base, DeclSpecs *ds) const { // Handle more complex anonymous declarations like // float (float **). sprintf(buf, "__anon_parameter_%d", i); - sym = new Symbol(buf, pos); + sym = new Symbol(buf, d->declarators[0]->pos); sym->type = d->declarators[0]->GetType(d->declSpecs); } } + if (d->declSpecs->storageClass != SC_NONE) + Error(sym->pos, "Storage class \"%s\" is illegal in " + "function parameter declaration for parameter \"%s\".", + lGetStorageClassName(d->declSpecs->storageClass), + sym->name.c_str()); + const ArrayType *at = dynamic_cast(sym->type); if (at != NULL) { // As in C, arrays are passed to functions as pointers to @@ -497,6 +514,7 @@ GetStructTypesNamesPositions(const std::vector &sd, std::vector *elementTypes, std::vector *elementNames, std::vector *elementPositions) { + std::set seenNames; for (unsigned int i = 0; i < sd.size(); ++i) { const Type *type = sd[i]->type; // FIXME: making this fake little DeclSpecs here is really @@ -523,6 +541,12 @@ GetStructTypesNamesPositions(const std::vector &sd, else elementTypes->push_back(sym->type); + if (seenNames.find(sym->name) != seenNames.end()) + Error(d->pos, "Struct member \"%s\" has same name as a " + "previously-declared member.", sym->name.c_str()); + else + seenNames.insert(sym->name); + elementNames->push_back(sym->name); elementPositions->push_back(sym->pos); } diff --git a/expr.cpp b/expr.cpp index 1ddabb44..f6800b3d 100644 --- a/expr.cpp +++ b/expr.cpp @@ -2155,7 +2155,12 @@ AssignExpr::TypeCheck() { return NULL; } } - else + else if (dynamic_cast(lhsType) != NULL) { + Error(pos, "Illegal to assign to array type \"%s\".", + lhsType->GetString().c_str()); + return NULL; + } + else rvalue = TypeConvertExpr(rvalue, lhsType, lOpString(op)); if (rvalue == NULL) @@ -2755,6 +2760,12 @@ ExprList::TypeCheck() { llvm::Constant * ExprList::GetConstant(const Type *type) const { + if (exprs.size() == 1 && + (dynamic_cast(type) != NULL || + dynamic_cast(type) != NULL || + dynamic_cast(type) != NULL)) + return exprs[0]->GetConstant(type); + const CollectionType *collectionType = dynamic_cast(type); if (collectionType == NULL) diff --git a/func.cpp b/func.cpp index 7c6895a2..d2504351 100644 --- a/func.cpp +++ b/func.cpp @@ -339,6 +339,13 @@ Function::GenerateIR() { llvm::Function *function = sym->function; assert(function != NULL); + // But if that function has a definition, we don't want to redefine it. + if (function->empty() == false) { + Error(sym->pos, "Ignoring redefinition of function \"%s\".", + sym->name.c_str()); + return; + } + // Figure out a reasonable source file position for the start of the // function body. If possible, get the position of the first actual // non-StmtList statment... diff --git a/module.cpp b/module.cpp index ca2e6fc9..e9e96cea 100644 --- a/module.cpp +++ b/module.cpp @@ -400,10 +400,40 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) { return; } - if (symbolTable->LookupFunction(funSym->name.c_str(), - functionType) != NULL) - // Ignore redeclaration of a function with the same name and type - return; + std::vector *overloadFuncs = + symbolTable->LookupFunction(funSym->name.c_str()); + if (overloadFuncs != NULL) { + for (unsigned int i = 0; i < overloadFuncs->size(); ++i) { + Symbol *overloadFunc = (*overloadFuncs)[i]; + + // Check for a redeclaration of a function with the same + // name and type + if (Type::Equal(overloadFunc->type, functionType)) + return; + + // If all of the parameter types match but the return type is + // different, return an error--overloading by return type isn't + // allowed. + const FunctionType *ofType = + dynamic_cast(overloadFunc->type); + assert(ofType != NULL); + if (ofType->GetNumParameters() == functionType->GetNumParameters()) { + int i; + for (i = 0; i < functionType->GetNumParameters(); ++i) { + if (Type::Equal(ofType->GetParameterType(i), + functionType->GetParameterType(i)) == false) + break; + } + if (i == functionType->GetNumParameters()) { + Error(funSym->pos, "Illegal to overload function by return " + "type only (previous declaration was at line %d of " + "file %s).", overloadFunc->pos.first_line, + overloadFunc->pos.name); + return; + } + } + } + } if (funSym->storageClass == SC_EXTERN_C) { // Make sure the user hasn't supplied both an 'extern "C"' and a @@ -538,13 +568,6 @@ Module::AddFunctionDeclaration(Symbol *funSym, bool isInline) { } funSym->function = function; - // But if that function has a definition, we don't want to redefine it. - if (!function->empty()) { - Warning(funSym->pos, "Ignoring redefinition of function \"%s\".", - funSym->name.c_str()); - return; - } - // Finally, we know all is good and we can add the function to the // symbol table bool ok = symbolTable->AddFunction(funSym); diff --git a/parse.yy b/parse.yy index 6d4a6d78..2d62d4d8 100644 --- a/parse.yy +++ b/parse.yy @@ -34,7 +34,7 @@ %locations /* supress shift-reduces conflict message for dangling else */ -/* one for 'if', one for 'uif' */ +/* one for 'if', one for 'cif' */ %expect 2 %pure-parser @@ -96,6 +96,8 @@ static void lAddThreadIndexCountToSymbolTable(SourcePos pos); static std::string lGetAlternates(std::vector &alternates); static const char *lGetStorageClassString(StorageClass sc); static bool lGetConstantInt(Expr *expr, int *value, SourcePos pos, const char *usage); +static EnumType *lCreateEnumType(const char *name, std::vector *enums, + SourcePos pos); static void lFinalizeEnumeratorSymbols(std::vector &enums, const EnumType *enumType); @@ -732,9 +734,18 @@ specifier_qualifier_list $$ = $2; } } - else { - UNIMPLEMENTED; + else if ($1 == TYPEQUAL_INLINE) { + Error(@1, "\"inline\" qualifier is illegal outside of " + "function declarations."); + $$ = $2; } + else if ($1 == TYPEQUAL_TASK) { + Error(@1, "\"task\" qualifier is illegal outside of " + "function declarations."); + $$ = $2; + } + else + FATAL("Unhandled type qualifier in parser."); } else $$ = NULL; @@ -773,32 +784,19 @@ enum_identifier enum_specifier : TOKEN_ENUM '{' enumerator_list '}' { - if ($3 != NULL) { - EnumType *enumType = new EnumType(@1); - - lFinalizeEnumeratorSymbols(*$3, enumType); - for (unsigned int i = 0; i < $3->size(); ++i) - m->symbolTable->AddVariable((*$3)[i]); - enumType->SetEnumerators(*$3); - $$ = enumType; - } - else - $$ = NULL; + $$ = lCreateEnumType(NULL, $3, @1); } | TOKEN_ENUM enum_identifier '{' enumerator_list '}' { - if ($4 != NULL) { - EnumType *enumType = new EnumType($2, $2); - m->symbolTable->AddType($2, enumType, @2); - - lFinalizeEnumeratorSymbols(*$4, enumType); - for (unsigned int i = 0; i < $4->size(); ++i) - m->symbolTable->AddVariable((*$4)[i]); - enumType->SetEnumerators(*$4); - $$ = enumType; - } - else - $$ = NULL; + $$ = lCreateEnumType($2, $4, @2); + } + | TOKEN_ENUM '{' enumerator_list ',' '}' + { + $$ = lCreateEnumType(NULL, $3, @1); + } + | TOKEN_ENUM enum_identifier '{' enumerator_list ',' '}' + { + $$ = lCreateEnumType($2, $4, @2); } | TOKEN_ENUM enum_identifier { @@ -1579,6 +1577,23 @@ lGetConstantInt(Expr *expr, int *value, SourcePos pos, const char *usage) { } +static EnumType * +lCreateEnumType(const char *name, std::vector *enums, SourcePos pos) { + if (enums == NULL) + return NULL; + + EnumType *enumType = name ? new EnumType(name, pos) : new EnumType(pos); + if (name != NULL) + m->symbolTable->AddType(name, enumType, pos); + + lFinalizeEnumeratorSymbols(*enums, enumType); + for (unsigned int i = 0; i < enums->size(); ++i) + m->symbolTable->AddVariable((*enums)[i]); + enumType->SetEnumerators(*enums); + return enumType; +} + + /** Given an array of enumerator symbols, make sure each of them has a ConstExpr * in their Symbol::constValue member that stores their unsigned integer value. Symbols that had values explicitly provided diff --git a/stmt.cpp b/stmt.cpp index 8f49b9a5..93bc7569 100644 --- a/stmt.cpp +++ b/stmt.cpp @@ -182,10 +182,16 @@ lInitSymbol(llvm::Value *lvalue, const char *symName, const Type *symType, if (dynamic_cast(symType) != NULL || dynamic_cast(symType) != NULL || dynamic_cast(symType) != NULL) { - if (dynamic_cast(initExpr) != NULL) - Error(initExpr->pos, "Expression list initializers can't be used for " - "variable \"%s\' with type \"%s\".", symName, - symType->GetString().c_str()); + ExprList *elist = dynamic_cast(initExpr); + if (elist != NULL) { + if (elist->exprs.size() == 1) + lInitSymbol(lvalue, symName, symType, elist->exprs[0], ctx, + pos); + else + Error(initExpr->pos, "Expression list initializers can't be used for " + "variable \"%s\' with type \"%s\".", symName, + symType->GetString().c_str()); + } return; } diff --git a/tests/array-assignment-varying-control.ispc b/tests/array-assignment-varying-control.ispc deleted file mode 100644 index 53014a72..00000000 --- a/tests/array-assignment-varying-control.ispc +++ /dev/null @@ -1,27 +0,0 @@ - -export uniform int width() { return programCount; } - - - -struct Foo { float f; }; - -void f(uniform Foo foo[], float a) { - ++foo[a].f; -} - -export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { - float a = aFOO[programIndex]; - float f[40], g[40]; - for (uniform int i = 0; i < 40; ++i) { - f[i] = a; - g[i] = b; - } - if (a < 2) - f = g; - RET[programIndex] = f[a]; -} - -export void result(uniform float RET[]) { - RET[programIndex] = 1+programIndex; - RET[0] = 5; -} diff --git a/tests/init-atomic-with-expr-list.ispc b/tests/init-atomic-with-expr-list.ispc new file mode 100644 index 00000000..e3f2435d --- /dev/null +++ b/tests/init-atomic-with-expr-list.ispc @@ -0,0 +1,14 @@ + +export uniform int width() { return programCount; } + +int b = { 2. }; + +export void f_f(uniform float RET[], uniform float aFOO[]) { + float a = aFOO[programIndex]; + float aa = { a }; + RET[programIndex] = aa+b; +} + +export void result(uniform float RET[]) { + RET[programIndex] = 3 + 1*programIndex; +} diff --git a/tests/test-55.ispc b/tests/test-55.ispc deleted file mode 100644 index fc8803d5..00000000 --- a/tests/test-55.ispc +++ /dev/null @@ -1,10 +0,0 @@ - -export uniform int width() { return programCount; } - - -export void f_v(uniform float RET[]) { RET[programIndex] = 1.; } -export void f_v(uniform float RET[]) { RET[programIndex] = 2.; } - -export void result(uniform float RET[]) { - RET[programIndex] = 1.000000; -} diff --git a/tests_errors/array-plus-equals.ispc b/tests_errors/array-plus-equals.ispc new file mode 100644 index 00000000..9d6f7d3f --- /dev/null +++ b/tests_errors/array-plus-equals.ispc @@ -0,0 +1,6 @@ +// Illegal to assign to array type "float[5]" + +void foo(float *x) { + float a[5] = { 1,2,3,4,5}; + a += 3; +} diff --git a/tests_errors/array-pointer-assign.ispc b/tests_errors/array-pointer-assign.ispc index 11744640..a179c332 100644 --- a/tests_errors/array-pointer-assign.ispc +++ b/tests_errors/array-pointer-assign.ispc @@ -1,4 +1,4 @@ -// ffofoof +// Illegal to assign to array type "float[5]" void foo(float *x) { float a[5] = { 1,2,3,4,5}; diff --git a/tests_errors/assign-struct-with-const-member-2.ispc b/tests_errors/assign-struct-with-const-member-2.ispc new file mode 100644 index 00000000..b2d80de1 --- /dev/null +++ b/tests_errors/assign-struct-with-const-member-2.ispc @@ -0,0 +1,14 @@ +// Illegal to assign to type "uniform struct Bar" in type "uniform struct Foo" due to element "a" with type "const int32" + +struct Bar { + const int a; +}; + +struct Foo { + struct Bar b; +}; + +void foo(Foo f) { + Foo g; + g = f; +} diff --git a/tests_errors/assign-struct-with-const-member.ispc b/tests_errors/assign-struct-with-const-member.ispc index 396fb1f6..320a768b 100644 --- a/tests_errors/assign-struct-with-const-member.ispc +++ b/tests_errors/assign-struct-with-const-member.ispc @@ -1,4 +1,4 @@ -// ffofoof +// Illegal to assign to type "uniform struct Foo" due to element "a" with type "const int32" struct Foo { const int a; diff --git a/tests_errors/decl-3.ispc b/tests_errors/decl-3.ispc deleted file mode 100644 index 451ced22..00000000 --- a/tests_errors/decl-3.ispc +++ /dev/null @@ -1,5 +0,0 @@ -// Expression list initializers can't be used - -int func() { - int a = { 1 }; -} diff --git a/tests_errors/func-overload-by-return-type.ispc b/tests_errors/func-overload-by-return-type.ispc new file mode 100644 index 00000000..9eca6d0a --- /dev/null +++ b/tests_errors/func-overload-by-return-type.ispc @@ -0,0 +1,16 @@ +// Illegal to overload function by return type only + +float foo() { + int x = { 2 }; +} + +int y = { 2 }; + +void foo() { +//CO while (true) +//CO ; +//CO for (;;) +//CO ; + do ; while(1); +} + diff --git a/tests_errors/func-param-static.ispc b/tests_errors/func-param-static.ispc new file mode 100644 index 00000000..7fe506bf --- /dev/null +++ b/tests_errors/func-param-static.ispc @@ -0,0 +1,6 @@ +// Storage class "static" is illegal in function parameter declaration for parameter "x" + +void foo(static int x) { +} + + diff --git a/tests_errors/function-redefinition.ispc b/tests_errors/function-redefinition.ispc new file mode 100644 index 00000000..59d8bb23 --- /dev/null +++ b/tests_errors/function-redefinition.ispc @@ -0,0 +1,16 @@ +// Ignoring redefinition of function "foo". + +float foo() { + int x = { 2 }; +} + +int y = { 2 }; + +float foo() { +//CO while (true) +//CO ; +//CO for (;;) +//CO ; + do ; while(1); +} + diff --git a/tests_errors/struct-bad-qualifiers.ispc b/tests_errors/struct-bad-qualifiers.ispc new file mode 100644 index 00000000..3b3512cb --- /dev/null +++ b/tests_errors/struct-bad-qualifiers.ispc @@ -0,0 +1,5 @@ +// "task" qualifier is illegal outside of function declarations + +struct Foo { + task float x; +}; diff --git a/tests_errors/struct-with-repeated-member-name.ispc b/tests_errors/struct-with-repeated-member-name.ispc index 134ae3b7..38d12711 100644 --- a/tests_errors/struct-with-repeated-member-name.ispc +++ b/tests_errors/struct-with-repeated-member-name.ispc @@ -1,4 +1,4 @@ -// ffofoof +// Struct member "a" has same name as a previously-declared member struct Foo { int a, a; diff --git a/tests_errors/unsigned-float.ispc b/tests_errors/unsigned-float.ispc new file mode 100644 index 00000000..f97dc6dd --- /dev/null +++ b/tests_errors/unsigned-float.ispc @@ -0,0 +1,3 @@ +// "unsigned" qualifier is illegal with "float" type + +unsigned float foo = 1;