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:
2
ast.cpp
2
ast.cpp
@@ -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)
|
||||
|
||||
57
stmt.cpp
57
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<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
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,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
|
||||
|
||||
6
tests_errors/ref-initializer-1.ispc
Normal file
6
tests_errors/ref-initializer-1.ispc
Normal 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];
|
||||
}
|
||||
|
||||
6
tests_errors/ref-initializer-2.ispc
Normal file
6
tests_errors/ref-initializer-2.ispc
Normal 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];
|
||||
}
|
||||
|
||||
6
tests_errors/ref-initializer-3.ispc
Normal file
6
tests_errors/ref-initializer-3.ispc
Normal 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];
|
||||
}
|
||||
|
||||
5
tests_errors/return-ref-1.ispc
Normal file
5
tests_errors/return-ref-1.ispc
Normal 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;
|
||||
}
|
||||
5
tests_errors/return-ref-2.ispc
Normal file
5
tests_errors/return-ref-2.ispc
Normal 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];
|
||||
}
|
||||
Reference in New Issue
Block a user