Permalink
Browse files

Add checks about references to non-lvalues.

Both ReturnStmt and DeclStmt now check the values being associated
with references to make sure that they are legal (e.g. it's illegal
to assign a varying lvalue, or a compile-time constant to a reference
type).  Previously we didn't catch this and would end up hitting
assertions in LLVM when code did this stuff.

Mostly fixes issue #225 (except for adding a FAQ about what this
error message means.)
  • Loading branch information...
1 parent 637d076 commit c27418da776a719f76f46622cf49cd8ebfdeedd2 Matt Pharr committed Apr 4, 2012
View
@@ -153,7 +153,7 @@ WalkAST(ASTNode *node, ASTPreCallBackFunc preFunc, ASTPostCallBackFunc postFunc,
else if ((ls = dynamic_cast<LabeledStmt *>(node)) != NULL)
ls->stmt = (Stmt *)WalkAST(ls->stmt, preFunc, postFunc, data);
else if ((rs = dynamic_cast<ReturnStmt *>(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<StmtList *>(node)) != NULL) {
std::vector<Stmt *> &sls = sl->stmts;
for (unsigned int i = 0; i < sls.size(); ++i)
View
@@ -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<const ReferenceType *>(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");
}
View
6 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,15 +265,15 @@ class ForeachStmt : public Stmt {
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;
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
@@ -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];
+}
+
@@ -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];
+}
+
@@ -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];
+}
+
@@ -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;
+}
@@ -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];
+}
View
4 type.h
@@ -828,4 +828,8 @@ class FunctionType : public Type {
const std::vector<SourcePos> paramPositions;
};
+inline bool IsReferenceType(const Type *t) {
+ return dynamic_cast<const ReferenceType *>(t) != NULL;
+}
+
#endif // ISPC_TYPE_H

0 comments on commit c27418d

Please sign in to comment.