Prevent shader crash when using precision on boolean types
This commit is contained in:
parent
06c33cca18
commit
643e75bea9
2 changed files with 79 additions and 63 deletions
|
@ -4670,16 +4670,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
||||||
expr = _parse_array_constructor(p_block, p_function_info);
|
expr = _parse_array_constructor(p_block, p_function_info);
|
||||||
} else {
|
} else {
|
||||||
DataType datatype;
|
DataType datatype;
|
||||||
DataPrecision precision;
|
DataPrecision precision = PRECISION_DEFAULT;
|
||||||
bool precision_defined = false;
|
|
||||||
|
|
||||||
if (is_token_precision(tk.type)) {
|
if (is_token_precision(tk.type)) {
|
||||||
precision = get_token_precision(tk.type);
|
precision = get_token_precision(tk.type);
|
||||||
precision_defined = true;
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
datatype = get_token_datatype(tk.type);
|
datatype = get_token_datatype(tk.type);
|
||||||
|
if (precision != PRECISION_DEFAULT && _validate_precision(datatype, precision) != OK) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
|
||||||
if (tk.type == TK_BRACKET_OPEN) {
|
if (tk.type == TK_BRACKET_OPEN) {
|
||||||
|
@ -4697,7 +4699,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
||||||
OperatorNode *func = alloc_node<OperatorNode>();
|
OperatorNode *func = alloc_node<OperatorNode>();
|
||||||
func->op = OP_CONSTRUCT;
|
func->op = OP_CONSTRUCT;
|
||||||
|
|
||||||
if (precision_defined) {
|
if (precision != PRECISION_DEFAULT) {
|
||||||
func->return_precision_cache = precision;
|
func->return_precision_cache = precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6426,10 +6428,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
|
||||||
if (!is_struct) {
|
if (!is_struct) {
|
||||||
is_struct = shader->structs.has(tk.text); // check again.
|
is_struct = shader->structs.has(tk.text); // check again.
|
||||||
}
|
}
|
||||||
if (is_struct && precision != PRECISION_DEFAULT) {
|
|
||||||
_set_error(RTR("The precision modifier cannot be used on structs."));
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
if (!is_token_nonvoid_datatype(tk.type)) {
|
if (!is_token_nonvoid_datatype(tk.type)) {
|
||||||
_set_error(RTR("Expected variable type after precision modifier."));
|
_set_error(RTR("Expected variable type after precision modifier."));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
|
@ -6449,6 +6447,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
int array_size = 0;
|
int array_size = 0;
|
||||||
bool fixed_array_size = false;
|
bool fixed_array_size = false;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@ -6600,10 +6602,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
|
||||||
if (is_token_precision(tk.type)) {
|
if (is_token_precision(tk.type)) {
|
||||||
precision2 = get_token_precision(tk.type);
|
precision2 = get_token_precision(tk.type);
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
if (shader->structs.has(tk.text)) {
|
|
||||||
_set_error(RTR("The precision modifier cannot be used on structs."));
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
if (!is_token_nonvoid_datatype(tk.type)) {
|
if (!is_token_nonvoid_datatype(tk.type)) {
|
||||||
_set_error(RTR("Expected data type after precision modifier."));
|
_set_error(RTR("Expected data type after precision modifier."));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
|
@ -6624,6 +6622,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
|
||||||
type2 = get_token_datatype(tk.type);
|
type2 = get_token_datatype(tk.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (precision2 != PRECISION_DEFAULT && _validate_precision(type2, precision2) != OK) {
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
int array_size2 = 0;
|
int array_size2 = 0;
|
||||||
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
@ -7427,6 +7429,25 @@ String ShaderLanguage::_get_qualifier_str(ArgumentQualifier p_qualifier) const {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error ShaderLanguage::_validate_precision(DataType p_type, DataPrecision p_precision) {
|
||||||
|
switch (p_type) {
|
||||||
|
case TYPE_STRUCT: {
|
||||||
|
_set_error(RTR("The precision modifier cannot be used on structs."));
|
||||||
|
return FAILED;
|
||||||
|
} break;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
case TYPE_BVEC2:
|
||||||
|
case TYPE_BVEC3:
|
||||||
|
case TYPE_BVEC4: {
|
||||||
|
_set_error(RTR("The precision modifier cannot be used on boolean types."));
|
||||||
|
return FAILED;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
Error ShaderLanguage::_validate_datatype(DataType p_type) {
|
Error ShaderLanguage::_validate_datatype(DataType p_type) {
|
||||||
if (RenderingServer::get_singleton()->is_low_end()) {
|
if (RenderingServer::get_singleton()->is_low_end()) {
|
||||||
bool invalid_type = false;
|
bool invalid_type = false;
|
||||||
|
@ -7608,8 +7629,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
}
|
}
|
||||||
StringName struct_name = "";
|
StringName struct_name = "";
|
||||||
bool struct_dt = false;
|
bool struct_dt = false;
|
||||||
bool use_precision = false;
|
DataPrecision precision = PRECISION_DEFAULT;
|
||||||
DataPrecision precision = DataPrecision::PRECISION_DEFAULT;
|
|
||||||
|
|
||||||
if (tk.type == TK_STRUCT) {
|
if (tk.type == TK_STRUCT) {
|
||||||
_set_error(RTR("Nested structs are not allowed."));
|
_set_error(RTR("Nested structs are not allowed."));
|
||||||
|
@ -7618,7 +7638,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
|
|
||||||
if (is_token_precision(tk.type)) {
|
if (is_token_precision(tk.type)) {
|
||||||
precision = get_token_precision(tk.type);
|
precision = get_token_precision(tk.type);
|
||||||
use_precision = true;
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7630,10 +7649,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
}
|
}
|
||||||
#endif // DEBUG_ENABLED
|
#endif // DEBUG_ENABLED
|
||||||
struct_dt = true;
|
struct_dt = true;
|
||||||
if (use_precision) {
|
|
||||||
_set_error(RTR("The precision modifier cannot be used on structs."));
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_token_datatype(tk.type) && !struct_dt) {
|
if (!is_token_datatype(tk.type) && !struct_dt) {
|
||||||
|
@ -7642,6 +7657,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
} else {
|
} else {
|
||||||
type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type);
|
type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type);
|
||||||
|
|
||||||
|
if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == TYPE_VOID || is_sampler_type(type)) {
|
if (type == TYPE_VOID || is_sampler_type(type)) {
|
||||||
_set_error(vformat(RTR("A '%s' data type is not allowed here."), get_datatype_name(type)));
|
_set_error(vformat(RTR("A '%s' data type is not allowed here."), get_datatype_name(type)));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
|
@ -7762,7 +7781,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool precision_defined = false;
|
|
||||||
DataPrecision precision = PRECISION_DEFAULT;
|
DataPrecision precision = PRECISION_DEFAULT;
|
||||||
DataInterpolation interpolation = INTERPOLATION_SMOOTH;
|
DataInterpolation interpolation = INTERPOLATION_SMOOTH;
|
||||||
DataType type;
|
DataType type;
|
||||||
|
@ -7781,16 +7799,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
|
|
||||||
if (is_token_precision(tk.type)) {
|
if (is_token_precision(tk.type)) {
|
||||||
precision = get_token_precision(tk.type);
|
precision = get_token_precision(tk.type);
|
||||||
precision_defined = true;
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shader->structs.has(tk.text)) {
|
if (shader->structs.has(tk.text)) {
|
||||||
if (uniform) {
|
if (uniform) {
|
||||||
if (precision_defined) {
|
|
||||||
_set_error(RTR("The precision modifier cannot be used on structs."));
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
_set_error(vformat(RTR("The '%s' data type is not supported for uniforms."), "struct"));
|
_set_error(vformat(RTR("The '%s' data type is not supported for uniforms."), "struct"));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
} else {
|
} else {
|
||||||
|
@ -7806,6 +7819,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
|
|
||||||
type = get_token_datatype(tk.type);
|
type = get_token_datatype(tk.type);
|
||||||
|
|
||||||
|
if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == TYPE_VOID) {
|
if (type == TYPE_VOID) {
|
||||||
_set_error(vformat(RTR("The '%s' data type is not allowed here."), "void"));
|
_set_error(vformat(RTR("The '%s' data type is not allowed here."), "void"));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
|
@ -8249,10 +8266,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shader->structs.has(tk.text)) {
|
if (shader->structs.has(tk.text)) {
|
||||||
if (precision != PRECISION_DEFAULT) {
|
|
||||||
_set_error(RTR("The precision modifier cannot be used on structs."));
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
is_struct = true;
|
is_struct = true;
|
||||||
struct_name = tk.text;
|
struct_name = tk.text;
|
||||||
} else {
|
} else {
|
||||||
|
@ -8276,6 +8289,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
} else {
|
} else {
|
||||||
type = get_token_datatype(tk.type);
|
type = get_token_datatype(tk.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
prev_pos = _get_tkpos();
|
prev_pos = _get_tkpos();
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
|
||||||
|
@ -8652,44 +8670,41 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_const = false;
|
bool param_is_const = false;
|
||||||
if (tk.type == TK_CONST) {
|
if (tk.type == TK_CONST) {
|
||||||
is_const = true;
|
param_is_const = true;
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN;
|
ArgumentQualifier param_qualifier = ARGUMENT_QUALIFIER_IN;
|
||||||
|
|
||||||
if (tk.type == TK_ARG_IN) {
|
if (tk.type == TK_ARG_IN) {
|
||||||
qualifier = ARGUMENT_QUALIFIER_IN;
|
param_qualifier = ARGUMENT_QUALIFIER_IN;
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
} else if (tk.type == TK_ARG_OUT) {
|
} else if (tk.type == TK_ARG_OUT) {
|
||||||
if (is_const) {
|
if (param_is_const) {
|
||||||
_set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "out", "const"));
|
_set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "out", "const"));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
qualifier = ARGUMENT_QUALIFIER_OUT;
|
param_qualifier = ARGUMENT_QUALIFIER_OUT;
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
} else if (tk.type == TK_ARG_INOUT) {
|
} else if (tk.type == TK_ARG_INOUT) {
|
||||||
if (is_const) {
|
if (param_is_const) {
|
||||||
_set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "inout", "const"));
|
_set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "inout", "const"));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
qualifier = ARGUMENT_QUALIFIER_INOUT;
|
param_qualifier = ARGUMENT_QUALIFIER_INOUT;
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType ptype;
|
DataType param_type;
|
||||||
StringName pname;
|
StringName param_name;
|
||||||
StringName param_struct_name;
|
StringName param_struct_name;
|
||||||
DataPrecision pprecision = PRECISION_DEFAULT;
|
DataPrecision param_precision = PRECISION_DEFAULT;
|
||||||
bool use_precision = false;
|
|
||||||
int arg_array_size = 0;
|
int arg_array_size = 0;
|
||||||
|
|
||||||
if (is_token_precision(tk.type)) {
|
if (is_token_precision(tk.type)) {
|
||||||
pprecision = get_token_precision(tk.type);
|
param_precision = get_token_precision(tk.type);
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
use_precision = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_struct = false;
|
is_struct = false;
|
||||||
|
@ -8702,10 +8717,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
used_structs[param_struct_name].used = true;
|
used_structs[param_struct_name].used = true;
|
||||||
}
|
}
|
||||||
#endif // DEBUG_ENABLED
|
#endif // DEBUG_ENABLED
|
||||||
if (use_precision) {
|
|
||||||
_set_error(RTR("The precision modifier cannot be used on structs."));
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_struct && !is_token_datatype(tk.type)) {
|
if (!is_struct && !is_token_datatype(tk.type)) {
|
||||||
|
@ -8713,7 +8724,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qualifier == ARGUMENT_QUALIFIER_OUT || qualifier == ARGUMENT_QUALIFIER_INOUT) {
|
if (param_qualifier == ARGUMENT_QUALIFIER_OUT || param_qualifier == ARGUMENT_QUALIFIER_INOUT) {
|
||||||
if (is_sampler_type(get_token_datatype(tk.type))) {
|
if (is_sampler_type(get_token_datatype(tk.type))) {
|
||||||
_set_error(RTR("Opaque types cannot be output parameters."));
|
_set_error(RTR("Opaque types cannot be output parameters."));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
|
@ -8721,18 +8732,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_struct) {
|
if (is_struct) {
|
||||||
ptype = TYPE_STRUCT;
|
param_type = TYPE_STRUCT;
|
||||||
} else {
|
} else {
|
||||||
ptype = get_token_datatype(tk.type);
|
param_type = get_token_datatype(tk.type);
|
||||||
if (_validate_datatype(ptype) != OK) {
|
if (_validate_datatype(param_type) != OK) {
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
if (ptype == TYPE_VOID) {
|
if (param_type == TYPE_VOID) {
|
||||||
_set_error(RTR("Void type not allowed as argument."));
|
_set_error(RTR("Void type not allowed as argument."));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (param_precision != PRECISION_DEFAULT && _validate_precision(param_type, param_precision) != OK) {
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
|
||||||
if (tk.type == TK_BRACKET_OPEN) {
|
if (tk.type == TK_BRACKET_OPEN) {
|
||||||
|
@ -8747,32 +8762,32 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
pname = tk.text;
|
param_name = tk.text;
|
||||||
|
|
||||||
ShaderLanguage::IdentifierType itype;
|
ShaderLanguage::IdentifierType itype;
|
||||||
if (_find_identifier(func_node->body, false, builtins, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
|
if (_find_identifier(func_node->body, false, builtins, param_name, (ShaderLanguage::DataType *)nullptr, &itype)) {
|
||||||
if (itype != IDENTIFIER_FUNCTION) {
|
if (itype != IDENTIFIER_FUNCTION) {
|
||||||
_set_redefinition_error(String(pname));
|
_set_redefinition_error(String(param_name));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_builtin(p_functions, pname)) {
|
if (has_builtin(p_functions, param_name)) {
|
||||||
_set_redefinition_error(String(pname));
|
_set_redefinition_error(String(param_name));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionNode::Argument arg;
|
FunctionNode::Argument arg;
|
||||||
arg.type = ptype;
|
arg.type = param_type;
|
||||||
arg.name = pname;
|
arg.name = param_name;
|
||||||
arg.type_str = param_struct_name;
|
arg.type_str = param_struct_name;
|
||||||
arg.precision = pprecision;
|
arg.precision = param_precision;
|
||||||
arg.qualifier = qualifier;
|
arg.qualifier = param_qualifier;
|
||||||
arg.tex_argument_check = false;
|
arg.tex_argument_check = false;
|
||||||
arg.tex_builtin_check = false;
|
arg.tex_builtin_check = false;
|
||||||
arg.tex_argument_filter = FILTER_DEFAULT;
|
arg.tex_argument_filter = FILTER_DEFAULT;
|
||||||
arg.tex_argument_repeat = REPEAT_DEFAULT;
|
arg.tex_argument_repeat = REPEAT_DEFAULT;
|
||||||
arg.is_const = is_const;
|
arg.is_const = param_is_const;
|
||||||
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
if (tk.type == TK_BRACKET_OPEN) {
|
if (tk.type == TK_BRACKET_OPEN) {
|
||||||
|
|
|
@ -1038,6 +1038,7 @@ private:
|
||||||
|
|
||||||
static bool is_const_suffix_lut_initialized;
|
static bool is_const_suffix_lut_initialized;
|
||||||
|
|
||||||
|
Error _validate_precision(DataType p_type, DataPrecision p_precision);
|
||||||
Error _validate_datatype(DataType p_type);
|
Error _validate_datatype(DataType p_type);
|
||||||
bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b);
|
bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b);
|
||||||
bool _compare_datatypes_in_nodes(Node *a, Node *b);
|
bool _compare_datatypes_in_nodes(Node *a, Node *b);
|
||||||
|
|
Loading…
Add table
Reference in a new issue