diff --git a/ast.cpp b/ast.cpp index 445ef4c7..0c71cdc8 100644 --- a/ast.cpp +++ b/ast.cpp @@ -153,7 +153,7 @@ WalkAST(ASTNode *node, ASTPreCallBackFunc preFunc, ASTPostCallBackFunc postFunc, else if ((ls = dynamic_cast(node)) != NULL) ls->stmt = (Stmt *)WalkAST(ls->stmt, preFunc, postFunc, data); else if ((rs = dynamic_cast(node)) != NULL) - rs->val = (Expr *)WalkAST(rs->val, preFunc, postFunc, data); + rs->expr = (Expr *)WalkAST(rs->expr, preFunc, postFunc, data); else if ((sl = dynamic_cast(node)) != NULL) { std::vector &sls = sl->stmts; for (unsigned int i = 0; i < sls.size(); ++i) diff --git a/stmt.cpp b/stmt.cpp index 14032e7b..bf7fa661 100644 --- a/stmt.cpp +++ b/stmt.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2010-2011, Intel Corporation + Copyright (c) 2010-2012, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -40,6 +40,7 @@ #include "util.h" #include "expr.h" #include "type.h" +#include "func.h" #include "sym.h" #include "module.h" #include "llvmutil.h" @@ -167,11 +168,25 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const { } // References must have initializer expressions as well. - if (dynamic_cast(sym->type) && initExpr == NULL) { - Error(sym->pos, - "Must provide initializer for reference-type variable \"%s\".", - sym->name.c_str()); - continue; + if (IsReferenceType(sym->type) == true) { + if (initExpr == NULL) { + Error(sym->pos, "Must provide initializer for reference-type " + "variable \"%s\".", sym->name.c_str()); + continue; + } + if (IsReferenceType(initExpr->GetType()) == false) { + const Type *initLVType = initExpr->GetLValueType(); + if (initLVType == NULL) { + Error(initExpr->pos, "Initializer for reference-type variable " + "\"%s\" must have an lvalue type.", sym->name.c_str()); + continue; + } + if (initLVType->IsUniformType() == false) { + Error(initExpr->pos, "Initializer for reference-type variable " + "\"%s\" must have a uniform lvalue type.", sym->name.c_str()); + continue; + } + } } LLVM_TYPE_CONST llvm::Type *llvmType = sym->type->LLVMType(g->ctx); @@ -2173,8 +2188,8 @@ SwitchStmt::EstimateCost() const { /////////////////////////////////////////////////////////////////////////// // ReturnStmt -ReturnStmt::ReturnStmt(Expr *v, bool cc, SourcePos p) - : Stmt(p), val(v), +ReturnStmt::ReturnStmt(Expr *e, bool cc, SourcePos p) + : Stmt(p), expr(e), doCoherenceCheck(cc && !g->opt.disableCoherentControlFlow) { } @@ -2189,8 +2204,29 @@ ReturnStmt::EmitCode(FunctionEmitContext *ctx) const { return; } + // Make sure we're not trying to return a reference to something where + // that doesn't make sense + const Function *func = ctx->GetFunction(); + const Type *returnType = func->GetReturnType(); + if (IsReferenceType(returnType) == true && + IsReferenceType(expr->GetType()) == false) { + const Type *lvType = expr->GetLValueType(); + if (lvType == NULL) { + Error(expr->pos, "Illegal to return non-lvalue from function " + "returning reference type \"%s\".", + returnType->GetString().c_str()); + return; + } + else if (lvType->IsUniformType() == false) { + Error(expr->pos, "Illegal to return varying lvalue type from " + "function returning a reference type \"%s\".", + returnType->GetString().c_str()); + return; + } + } + ctx->SetDebugPos(pos); - ctx->CurrentLanesReturned(val, doCoherenceCheck); + ctx->CurrentLanesReturned(expr, doCoherenceCheck); } @@ -2210,7 +2246,8 @@ void ReturnStmt::Print(int indent) const { printf("%*c%sReturn Stmt", indent, ' ', doCoherenceCheck ? "Coherent " : ""); pos.Print(); - if (val) val->Print(); + if (expr) + expr->Print(); else printf("(void)"); printf("\n"); } diff --git a/stmt.h b/stmt.h index da418ec7..88115ab2 100644 --- a/stmt.h +++ b/stmt.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2010-2011, Intel Corporation + Copyright (c) 2010-2012, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -265,7 +265,7 @@ public: statement in the program. */ class ReturnStmt : public Stmt { public: - ReturnStmt(Expr *v, bool cc, SourcePos p); + ReturnStmt(Expr *e, bool cc, SourcePos p); void EmitCode(FunctionEmitContext *ctx) const; void Print(int indent) const; @@ -273,7 +273,7 @@ public: Stmt *TypeCheck(); int EstimateCost() const; - Expr *val; + Expr *expr; /** This indicates whether the generated code will check to see if no more program instances are currently running after the return, in which case the code can possibly jump to the end of the current diff --git a/tests_errors/ref-initializer-1.ispc b/tests_errors/ref-initializer-1.ispc new file mode 100644 index 00000000..c926c793 --- /dev/null +++ b/tests_errors/ref-initializer-1.ispc @@ -0,0 +1,6 @@ +// Initializer for reference-type variable "x" must have an lvalue type + +float &func(uniform float a[], int i, float f) { + float &x = 1.; // a[i]; +} + diff --git a/tests_errors/ref-initializer-2.ispc b/tests_errors/ref-initializer-2.ispc new file mode 100644 index 00000000..4612addf --- /dev/null +++ b/tests_errors/ref-initializer-2.ispc @@ -0,0 +1,6 @@ +// Initializer for reference-type variable "x" must have a uniform lvalue type + +float &func(uniform float a[], int i, float f) { + float &x = a[i]; +} + diff --git a/tests_errors/ref-initializer-3.ispc b/tests_errors/ref-initializer-3.ispc new file mode 100644 index 00000000..27833b54 --- /dev/null +++ b/tests_errors/ref-initializer-3.ispc @@ -0,0 +1,6 @@ +// Initializer for reference-type variable "x" must have a uniform lvalue type + +float &func(uniform int a[], int i, float f) { + float &x = a[i]; +} + diff --git a/tests_errors/return-ref-1.ispc b/tests_errors/return-ref-1.ispc new file mode 100644 index 00000000..fee20b18 --- /dev/null +++ b/tests_errors/return-ref-1.ispc @@ -0,0 +1,5 @@ +// Illegal to return non-lvalue from function returning reference type + +float &func(uniform float a[], int i, float f) { + return 1.f; +} diff --git a/tests_errors/return-ref-2.ispc b/tests_errors/return-ref-2.ispc new file mode 100644 index 00000000..6ed667c1 --- /dev/null +++ b/tests_errors/return-ref-2.ispc @@ -0,0 +1,5 @@ +// Illegal to return varying lvalue type from function returning a reference type + +float &func(uniform float a[], int i, float f) { + return a[i]; +} diff --git a/type.h b/type.h index 5c690e60..fdcc41e6 100644 --- a/type.h +++ b/type.h @@ -828,4 +828,8 @@ private: const std::vector paramPositions; }; +inline bool IsReferenceType(const Type *t) { + return dynamic_cast(t) != NULL; +} + #endif // ISPC_TYPE_H