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)
|
else if ((ls = dynamic_cast<LabeledStmt *>(node)) != NULL)
|
||||||
ls->stmt = (Stmt *)WalkAST(ls->stmt, preFunc, postFunc, data);
|
ls->stmt = (Stmt *)WalkAST(ls->stmt, preFunc, postFunc, data);
|
||||||
else if ((rs = dynamic_cast<ReturnStmt *>(node)) != NULL)
|
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) {
|
else if ((sl = dynamic_cast<StmtList *>(node)) != NULL) {
|
||||||
std::vector<Stmt *> &sls = sl->stmts;
|
std::vector<Stmt *> &sls = sl->stmts;
|
||||||
for (unsigned int i = 0; i < sls.size(); ++i)
|
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.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
|
#include "func.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "llvmutil.h"
|
#include "llvmutil.h"
|
||||||
@@ -167,11 +168,25 @@ DeclStmt::EmitCode(FunctionEmitContext *ctx) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// References must have initializer expressions as well.
|
// References must have initializer expressions as well.
|
||||||
if (dynamic_cast<const ReferenceType *>(sym->type) && initExpr == NULL) {
|
if (IsReferenceType(sym->type) == true) {
|
||||||
Error(sym->pos,
|
if (initExpr == NULL) {
|
||||||
"Must provide initializer for reference-type variable \"%s\".",
|
Error(sym->pos, "Must provide initializer for reference-type "
|
||||||
sym->name.c_str());
|
"variable \"%s\".", sym->name.c_str());
|
||||||
continue;
|
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);
|
LLVM_TYPE_CONST llvm::Type *llvmType = sym->type->LLVMType(g->ctx);
|
||||||
@@ -2173,8 +2188,8 @@ SwitchStmt::EstimateCost() const {
|
|||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// ReturnStmt
|
// ReturnStmt
|
||||||
|
|
||||||
ReturnStmt::ReturnStmt(Expr *v, bool cc, SourcePos p)
|
ReturnStmt::ReturnStmt(Expr *e, bool cc, SourcePos p)
|
||||||
: Stmt(p), val(v),
|
: Stmt(p), expr(e),
|
||||||
doCoherenceCheck(cc && !g->opt.disableCoherentControlFlow) {
|
doCoherenceCheck(cc && !g->opt.disableCoherentControlFlow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2189,8 +2204,29 @@ ReturnStmt::EmitCode(FunctionEmitContext *ctx) const {
|
|||||||
return;
|
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->SetDebugPos(pos);
|
||||||
ctx->CurrentLanesReturned(val, doCoherenceCheck);
|
ctx->CurrentLanesReturned(expr, doCoherenceCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2210,7 +2246,8 @@ void
|
|||||||
ReturnStmt::Print(int indent) const {
|
ReturnStmt::Print(int indent) const {
|
||||||
printf("%*c%sReturn Stmt", indent, ' ', doCoherenceCheck ? "Coherent " : "");
|
printf("%*c%sReturn Stmt", indent, ' ', doCoherenceCheck ? "Coherent " : "");
|
||||||
pos.Print();
|
pos.Print();
|
||||||
if (val) val->Print();
|
if (expr)
|
||||||
|
expr->Print();
|
||||||
else printf("(void)");
|
else printf("(void)");
|
||||||
printf("\n");
|
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.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
@@ -265,7 +265,7 @@ public:
|
|||||||
statement in the program. */
|
statement in the program. */
|
||||||
class ReturnStmt : public Stmt {
|
class ReturnStmt : public Stmt {
|
||||||
public:
|
public:
|
||||||
ReturnStmt(Expr *v, bool cc, SourcePos p);
|
ReturnStmt(Expr *e, bool cc, SourcePos p);
|
||||||
|
|
||||||
void EmitCode(FunctionEmitContext *ctx) const;
|
void EmitCode(FunctionEmitContext *ctx) const;
|
||||||
void Print(int indent) const;
|
void Print(int indent) const;
|
||||||
@@ -273,7 +273,7 @@ public:
|
|||||||
Stmt *TypeCheck();
|
Stmt *TypeCheck();
|
||||||
int EstimateCost() const;
|
int EstimateCost() const;
|
||||||
|
|
||||||
Expr *val;
|
Expr *expr;
|
||||||
/** This indicates whether the generated code will check to see if no
|
/** This indicates whether the generated code will check to see if no
|
||||||
more program instances are currently running after the return, in
|
more program instances are currently running after the return, in
|
||||||
which case the code can possibly jump to the end of the current
|
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