aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/ast.h13
-rw-r--r--mesalib/src/glsl/ast_function.cpp63
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp39
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp1
4 files changed, 100 insertions, 16 deletions
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h
index d899bc62a..1f78af87e 100644
--- a/mesalib/src/glsl/ast.h
+++ b/mesalib/src/glsl/ast.h
@@ -207,6 +207,7 @@ public:
subexpressions[1] = NULL;
subexpressions[2] = NULL;
primary_expression.identifier = (char *) identifier;
+ this->non_lvalue_description = NULL;
}
static const char *operator_string(enum ast_operators op);
@@ -234,6 +235,18 @@ public:
* \c ast_function_call
*/
exec_list expressions;
+
+ /**
+ * For things that can't be l-values, this describes what it is.
+ *
+ * This text is used by the code that generates IR for assignments to
+ * detect and emit useful messages for assignments to some things that
+ * can't be l-values. For example, pre- or post-incerement expressions.
+ *
+ * \note
+ * This pointer may be \c NULL.
+ */
+ const char *non_lvalue_description;
};
class ast_expression_bin : public ast_expression {
diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp
index 126b610d1..1c2e8613c 100644
--- a/mesalib/src/glsl/ast_function.cpp
+++ b/mesalib/src/glsl/ast_function.cpp
@@ -93,14 +93,21 @@ prototype_string(const glsl_type *return_type, const char *name,
return str;
}
+/**
+ * If a function call is generated, \c call_ir will point to it on exit.
+ * Otherwise \c call_ir will be set to \c NULL.
+ */
static ir_rvalue *
generate_call(exec_list *instructions, ir_function_signature *sig,
YYLTYPE *loc, exec_list *actual_parameters,
+ ir_call **call_ir,
struct _mesa_glsl_parse_state *state)
{
void *ctx = state;
exec_list post_call_conversions;
+ *call_ir = NULL;
+
/* Verify that 'out' and 'inout' actual parameters are lvalues. This
* isn't done in ir_function::matching_signature because that function
* cannot generate the necessary diagnostics.
@@ -256,10 +263,12 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
deref = new(ctx) ir_dereference_variable(var);
ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL);
instructions->push_tail(assign);
+ *call_ir = call;
deref = new(ctx) ir_dereference_variable(var);
} else {
instructions->push_tail(call);
+ *call_ir = call;
deref = NULL;
}
instructions->append_list(&post_call_conversions);
@@ -269,6 +278,7 @@ generate_call(exec_list *instructions, ir_function_signature *sig,
static ir_rvalue *
match_function_by_name(exec_list *instructions, const char *name,
YYLTYPE *loc, exec_list *actual_parameters,
+ ir_call **call_ir,
struct _mesa_glsl_parse_state *state)
{
void *ctx = state;
@@ -342,7 +352,8 @@ done:
}
/* Finally, generate a call instruction. */
- return generate_call(instructions, sig, loc, actual_parameters, state);
+ return generate_call(instructions, sig, loc, actual_parameters,
+ call_ir, state);
} else {
char *str = prototype_string(NULL, name, actual_parameters);
@@ -1442,9 +1453,53 @@ ast_function_expression::hir(exec_list *instructions,
process_parameters(instructions, &actual_parameters, &this->expressions,
state);
- return match_function_by_name(instructions,
- id->primary_expression.identifier, & loc,
- &actual_parameters, state);
+ ir_call *call = NULL;
+ ir_rvalue *const value =
+ match_function_by_name(instructions,
+ id->primary_expression.identifier,
+ &loc, &actual_parameters, &call, state);
+
+ if (call != NULL) {
+ /* If a function was found, make sure that none of the 'out' or 'inout'
+ * parameters violate the extra l-value rules.
+ */
+ ir_function_signature *f = call->get_callee();
+ assert(f != NULL);
+
+ exec_node *formal_node = f->parameters.head;
+
+ foreach_list (actual_node, &this->expressions) {
+ /* Both parameter lists had better be the same length!
+ */
+ assert(!actual_node->is_tail_sentinel());
+
+ const ir_variable *const formal_parameter =
+ (ir_variable *) formal_node;
+ const ast_expression *const actual_parameter =
+ exec_node_data(ast_expression, actual_node, link);
+
+ if ((formal_parameter->mode == ir_var_out
+ || formal_parameter->mode == ir_var_inout)
+ && actual_parameter->non_lvalue_description != NULL) {
+ YYLTYPE loc = actual_parameter->get_location();
+
+ _mesa_glsl_error(&loc, state,
+ "function parameter '%s %s' references a %s",
+ (formal_parameter->mode == ir_var_out)
+ ? "out" : "inout",
+ formal_parameter->name,
+ actual_parameter->non_lvalue_description);
+ return ir_call::get_error_instruction(ctx);
+ }
+
+ /* Only advance the formal_node pointer here because the
+ * foreach_list business already advances actual_node.
+ */
+ formal_node = formal_node->next;
+ }
+ }
+
+ return value;
}
return ir_call::get_error_instruction(ctx);
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index f0c921875..1aebca40f 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -664,6 +664,7 @@ mark_whole_array_access(ir_rvalue *access)
ir_rvalue *
do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
+ const char *non_lvalue_description,
ir_rvalue *lhs, ir_rvalue *rhs, bool is_initializer,
YYLTYPE lhs_loc)
{
@@ -671,8 +672,13 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
if (!error_emitted) {
- if (lhs->variable_referenced() != NULL
- && lhs->variable_referenced()->read_only) {
+ if (non_lvalue_description != NULL) {
+ _mesa_glsl_error(&lhs_loc, state,
+ "assignment to %s",
+ non_lvalue_description);
+ error_emitted = true;
+ } else if (lhs->variable_referenced() != NULL
+ && lhs->variable_referenced()->read_only) {
_mesa_glsl_error(&lhs_loc, state,
"assignment to read-only variable '%s'",
lhs->variable_referenced()->name);
@@ -769,11 +775,6 @@ get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue)
instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
lvalue, NULL));
- /* Once we've created this temporary, mark it read only so it's no
- * longer considered an lvalue.
- */
- var->read_only = true;
-
return new(ctx) ir_dereference_variable(var);
}
@@ -1030,7 +1031,9 @@ ast_expression::hir(exec_list *instructions,
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = this->subexpressions[1]->hir(instructions, state);
- result = do_assignment(instructions, state, op[0], op[1], false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0], op[1], false,
this->subexpressions[0]->get_location());
error_emitted = result->type->is_error();
break;
@@ -1310,6 +1313,7 @@ ast_expression::hir(exec_list *instructions,
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = (op[0]->type->is_error());
@@ -1335,6 +1339,7 @@ ast_expression::hir(exec_list *instructions,
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = type->is_error();
@@ -1349,8 +1354,9 @@ ast_expression::hir(exec_list *instructions,
&loc);
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
- result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
- temp_rhs, false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
break;
@@ -1365,8 +1371,9 @@ ast_expression::hir(exec_list *instructions,
state, &loc);
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
- result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
- temp_rhs, false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
break;
@@ -1463,6 +1470,9 @@ ast_expression::hir(exec_list *instructions,
case ast_pre_inc:
case ast_pre_dec: {
+ this->non_lvalue_description = (this->oper == ast_pre_inc)
+ ? "pre-increment operation" : "pre-decrement operation";
+
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = constant_one_for_inc_dec(ctx, op[0]->type);
@@ -1473,6 +1483,7 @@ ast_expression::hir(exec_list *instructions,
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error();
@@ -1481,6 +1492,8 @@ ast_expression::hir(exec_list *instructions,
case ast_post_inc:
case ast_post_dec: {
+ this->non_lvalue_description = (this->oper == ast_post_inc)
+ ? "post-increment operation" : "post-decrement operation";
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = constant_one_for_inc_dec(ctx, op[0]->type);
@@ -1498,6 +1511,7 @@ ast_expression::hir(exec_list *instructions,
result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL));
(void)do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
@@ -2365,6 +2379,7 @@ process_initializer(ir_variable *var, ast_declaration *decl,
const glsl_type *initializer_type;
if (!type->qualifier.flags.q.uniform) {
result = do_assignment(initializer_instructions, state,
+ NULL,
lhs, rhs, true,
type->get_location());
initializer_type = result->type;
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index 0b4ccac53..0b53232e9 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -626,6 +626,7 @@ ast_expression::ast_expression(int oper,
this->subexpressions[0] = ex0;
this->subexpressions[1] = ex1;
this->subexpressions[2] = ex2;
+ this->non_lvalue_description = NULL;
}