From b2611c198ec7a81db1bb9b00abefe84d6d73072e Mon Sep 17 00:00:00 2001 From: Chaosus Date: Tue, 13 Aug 2024 11:38:41 +0300 Subject: [PATCH] Fix shader incorrectly expects `int` on `uint` and vice-versa in cases --- servers/rendering/shader_language.cpp | 129 ++++++++++++++------------ servers/rendering/shader_language.h | 3 + 2 files changed, 74 insertions(+), 58 deletions(-) diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 2249cd2010f..5a3c5d2fd09 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(); 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 constants; - for (ShaderLanguage::Node *statement : switch_block->statements) { // Checks for duplicates. - ControlFlowNode *flow = static_cast(statement); - if (flow) { - if (flow->flow_op == FLOW_OP_CASE) { - if (flow->expressions[0]->type == Node::NODE_TYPE_CONSTANT) { - ConstantNode *cn = static_cast(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(flow->expressions[0]); - if (!vn) { - return ERR_PARSE_ERROR; - } - Vector 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(); vn->name = tk.text; + { + Vector 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 { - Scalar v; - if (tk.type == TK_UINT_CONSTANT) { - v.uint = (uint32_t)tk.constant; - } else { - v.sint = (int)tk.constant * sign; - } - ConstantNode *cn = alloc_node(); + Scalar v; + 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 { + 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; + } 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 ba02e181b99..b0d579dfe76 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 constants; + BlockNode() : Node(NODE_TYPE_BLOCK) {} };