summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2024-09-12 09:17:43 +0200
committerRémi Verschelde <rverschelde@gmail.com>2024-09-12 09:17:43 +0200
commit8d9a446397f0e9d9527aaefb05cd4a6f95468cd0 (patch)
tree27da6e9b8b473725e26ceb6d468c5b02cf07491b
parentcd9da3344f5db4cea5af43ddeeba9629cdc538e2 (diff)
parentb2611c198ec7a81db1bb9b00abefe84d6d73072e (diff)
downloadredot-engine-8d9a446397f0e9d9527aaefb05cd4a6f95468cd0.tar.gz
Merge pull request #95473 from Chaosus/shader_fix_switch_bugs
Fix shader incorrectly expects `int` on `uint` and vice-versa in cases
-rw-r--r--servers/rendering/shader_language.cpp123
-rw-r--r--servers/rendering/shader_language.h3
2 files changed, 71 insertions, 55 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 2249cd2010..5a3c5d2fd0 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -8071,12 +8071,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!n) {
return ERR_PARSE_ERROR;
}
- {
- const ShaderLanguage::DataType switch_type = n->get_datatype();
- if (switch_type != TYPE_INT && switch_type != TYPE_UINT) {
- _set_error(RTR("Expected an integer expression."));
- return ERR_PARSE_ERROR;
- }
+ const ShaderLanguage::DataType data_type = n->get_datatype();
+ if (data_type != TYPE_INT && data_type != TYPE_UINT) {
+ _set_error(RTR("Expected an integer or unsigned integer expression."));
+ return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
@@ -8091,11 +8089,22 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
BlockNode *switch_block = alloc_node<BlockNode>();
switch_block->block_type = BlockNode::BLOCK_TYPE_SWITCH;
switch_block->parent_block = p_block;
+ switch_block->expected_type = data_type;
cf->expressions.push_back(n);
cf->blocks.push_back(switch_block);
p_block->statements.push_back(cf);
- int prev_type = TK_CF_CASE;
+ pos = _get_tkpos();
+ tk = _get_token();
+ TokenType prev_type;
+ if (tk.type == TK_CF_CASE || tk.type == TK_CF_DEFAULT) {
+ prev_type = tk.type;
+ _set_tkpos(pos);
+ } else {
+ _set_expected_error("case", "default");
+ return ERR_PARSE_ERROR;
+ }
+
while (true) { // Go-through multiple cases.
if (_parse_block(switch_block, p_function_info, true, true, false) != OK) {
@@ -8117,43 +8126,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
_set_tkpos(pos);
continue;
} else {
- HashSet<int> constants;
- for (ShaderLanguage::Node *statement : switch_block->statements) { // Checks for duplicates.
- ControlFlowNode *flow = static_cast<ControlFlowNode *>(statement);
- if (flow) {
- if (flow->flow_op == FLOW_OP_CASE) {
- if (flow->expressions[0]->type == Node::NODE_TYPE_CONSTANT) {
- ConstantNode *cn = static_cast<ConstantNode *>(flow->expressions[0]);
- if (!cn || cn->values.is_empty()) {
- return ERR_PARSE_ERROR;
- }
- if (constants.has(cn->values[0].sint)) {
- _set_error(vformat(RTR("Duplicated case label: %d."), cn->values[0].sint));
- return ERR_PARSE_ERROR;
- }
- constants.insert(cn->values[0].sint);
- } else if (flow->expressions[0]->type == Node::NODE_TYPE_VARIABLE) {
- VariableNode *vn = static_cast<VariableNode *>(flow->expressions[0]);
- if (!vn) {
- return ERR_PARSE_ERROR;
- }
- Vector<Scalar> v = { Scalar() };
- _find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v);
- if (constants.has(v[0].sint)) {
- _set_error(vformat(RTR("Duplicated case label: %d."), v[0].sint));
- return ERR_PARSE_ERROR;
- }
- constants.insert(v[0].sint);
- }
- } else if (flow->flow_op == FLOW_OP_DEFAULT) {
- continue;
- } else {
- return ERR_PARSE_ERROR;
- }
- } else {
- return ERR_PARSE_ERROR;
- }
- }
break;
}
}
@@ -8184,36 +8156,77 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!tk.is_integer_constant()) {
bool correct_constant_expression = false;
- DataType data_type;
if (tk.type == TK_IDENTIFIER) {
+ DataType data_type;
bool is_const;
+
_find_identifier(p_block, false, p_function_info, tk.text, &data_type, nullptr, &is_const);
- if (is_const) {
- if (data_type == TYPE_INT) {
- correct_constant_expression = true;
- }
+ if (is_const && data_type == p_block->expected_type) {
+ correct_constant_expression = true;
}
}
+
if (!correct_constant_expression) {
- _set_error(RTR("Expected an integer constant."));
+ if (p_block->expected_type == TYPE_UINT) {
+ _set_error(RTR("Expected an unsigned integer constant."));
+ } else {
+ _set_error(RTR("Expected an integer constant."));
+ }
return ERR_PARSE_ERROR;
}
VariableNode *vn = alloc_node<VariableNode>();
vn->name = tk.text;
+ {
+ Vector<Scalar> v;
+ DataType data_type;
+
+ _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, nullptr, nullptr, nullptr, &v);
+ if (data_type == TYPE_INT) {
+ if (p_block->constants.has(v[0].sint)) {
+ _set_error(vformat(RTR("Duplicated case label: %d."), v[0].sint));
+ return ERR_PARSE_ERROR;
+ }
+ p_block->constants.insert(v[0].sint);
+ } else {
+ if (p_block->constants.has(v[0].uint)) {
+ _set_error(vformat(RTR("Duplicated case label: %d."), v[0].uint));
+ return ERR_PARSE_ERROR;
+ }
+ p_block->constants.insert(v[0].uint);
+ }
+ }
n = vn;
} else {
+ ConstantNode *cn = alloc_node<ConstantNode>();
Scalar v;
- if (tk.type == TK_UINT_CONSTANT) {
+ if (p_block->expected_type == TYPE_UINT) {
+ if (tk.type != TK_UINT_CONSTANT) {
+ _set_error(RTR("Expected an unsigned integer constant."));
+ return ERR_PARSE_ERROR;
+ }
v.uint = (uint32_t)tk.constant;
+ if (p_block->constants.has(v.uint)) {
+ _set_error(vformat(RTR("Duplicated case label: %d."), v.uint));
+ return ERR_PARSE_ERROR;
+ }
+ p_block->constants.insert(v.uint);
+ cn->datatype = TYPE_UINT;
} else {
- v.sint = (int)tk.constant * sign;
+ if (tk.type != TK_INT_CONSTANT) {
+ _set_error(RTR("Expected an integer constant."));
+ return ERR_PARSE_ERROR;
+ }
+ v.sint = (int32_t)tk.constant * sign;
+ if (p_block->constants.has(v.sint)) {
+ _set_error(vformat(RTR("Duplicated case label: %d."), v.sint));
+ return ERR_PARSE_ERROR;
+ }
+ p_block->constants.insert(v.sint);
+ cn->datatype = TYPE_INT;
}
-
- ConstantNode *cn = alloc_node<ConstantNode>();
cn->values.push_back(v);
- cn->datatype = (tk.type == TK_UINT_CONSTANT ? TYPE_UINT : TYPE_INT);
n = cn;
}
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index ba02e181b9..b0d579dfe7 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -544,6 +544,9 @@ public:
bool use_comma_between_statements = false;
bool use_op_eval = true;
+ DataType expected_type = TYPE_VOID;
+ HashSet<int> constants;
+
BlockNode() :
Node(NODE_TYPE_BLOCK) {}
};