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.)
This commit is contained in:
Matt Pharr
2012-04-04 05:56:22 -07:00
parent 637d076e99
commit c27418da77
9 changed files with 83 additions and 14 deletions

View File

@@ -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 File

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

6
stmt.h
View File

@@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

4
type.h
View File

@@ -828,4 +828,8 @@ private:
const std::vector<SourcePos> paramPositions;
};
inline bool IsReferenceType(const Type *t) {
return dynamic_cast<const ReferenceType *>(t) != NULL;
}
#endif // ISPC_TYPE_H