diff options
-rw-r--r-- | core/error/error_macros.h | 14 | ||||
-rw-r--r-- | core/templates/safe_refcount.h | 20 | ||||
-rw-r--r-- | core/variant/variant.cpp | 75 | ||||
-rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 6 | ||||
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 52 | ||||
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 46 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 9 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/parser/features/multiline_assert.gd | 24 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/parser/features/multiline_assert.out | 2 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/runtime/features/await_on_void.gd | 7 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/runtime/features/await_on_void.out | 2 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd | 45 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out | 2 | ||||
-rw-r--r-- | platform/ios/device_metrics.m | 242 |
15 files changed, 356 insertions, 192 deletions
diff --git a/core/error/error_macros.h b/core/error/error_macros.h index f651ef57a3..63a2d22416 100644 --- a/core/error/error_macros.h +++ b/core/error/error_macros.h @@ -33,7 +33,7 @@ #include "core/typedefs.h" -#include "core/templates/safe_refcount.h" +#include <atomic> // We'd normally use safe_refcount.h, but that would cause circular includes. class String; @@ -737,10 +737,10 @@ void _err_flush_stdout(); */ #define WARN_DEPRECATED \ if (true) { \ - static SafeFlag warning_shown; \ - if (!warning_shown.is_set()) { \ + static std::atomic<bool> warning_shown; \ + if (!warning_shown.load()) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, ERR_HANDLER_WARNING); \ - warning_shown.set(); \ + warning_shown.store(true); \ } \ } else \ ((void)0) @@ -750,10 +750,10 @@ void _err_flush_stdout(); */ #define WARN_DEPRECATED_MSG(m_msg) \ if (true) { \ - static SafeFlag warning_shown; \ - if (!warning_shown.is_set()) { \ + static std::atomic<bool> warning_shown; \ + if (!warning_shown.load()) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, ERR_HANDLER_WARNING); \ - warning_shown.set(); \ + warning_shown.store(true); \ } \ } else \ ((void)0) diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h index 4d32e421cd..58ed019287 100644 --- a/core/templates/safe_refcount.h +++ b/core/templates/safe_refcount.h @@ -33,6 +33,10 @@ #include "core/typedefs.h" +#ifdef DEV_ENABLED +#include "core/error/error_macros.h" +#endif + #include <atomic> #include <type_traits> @@ -163,6 +167,16 @@ public: class SafeRefCount { SafeNumeric<uint32_t> count; +#ifdef DEV_ENABLED + _ALWAYS_INLINE_ void _check_unref_sanity() { + // This won't catch every misuse, but it's better than nothing. + CRASH_COND_MSG(count.get() == 0, + "Trying to unreference a SafeRefCount which is already zero is wrong and a symptom of it being misused.\n" + "Upon a SafeRefCount reaching zero any object whose lifetime is tied to it, as well as the ref count itself, must be destroyed.\n" + "Moreover, to guarantee that, no multiple threads should be racing to do the final unreferencing to zero."); + } +#endif + public: _ALWAYS_INLINE_ bool ref() { // true on success return count.conditional_increment() != 0; @@ -173,10 +187,16 @@ public: } _ALWAYS_INLINE_ bool unref() { // true if must be disposed of +#ifdef DEV_ENABLED + _check_unref_sanity(); +#endif return count.decrement() == 0; } _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of +#ifdef DEV_ENABLED + _check_unref_sanity(); +#endif return count.decrement(); } diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 7039a5d9c4..bff6656a88 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -3240,33 +3240,34 @@ uint32_t Variant::recursive_hash(int recursion_count) const { } #define hash_compare_scalar(p_lhs, p_rhs) \ - ((p_lhs) == (p_rhs)) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)) - -#define hash_compare_vector2(p_lhs, p_rhs) \ - (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \ - (hash_compare_scalar((p_lhs).y, (p_rhs).y)) - -#define hash_compare_vector3(p_lhs, p_rhs) \ - (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \ - (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ - (hash_compare_scalar((p_lhs).z, (p_rhs).z)) -#define hash_compare_vector4(p_lhs, p_rhs) \ - (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \ - (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ - (hash_compare_scalar((p_lhs).z, (p_rhs).z)) && \ - (hash_compare_scalar((p_lhs).w, (p_rhs).w)) - -#define hash_compare_quaternion(p_lhs, p_rhs) \ - (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \ - (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ - (hash_compare_scalar((p_lhs).z, (p_rhs).z)) && \ - (hash_compare_scalar((p_lhs).w, (p_rhs).w)) - -#define hash_compare_color(p_lhs, p_rhs) \ - (hash_compare_scalar((p_lhs).r, (p_rhs).r)) && \ - (hash_compare_scalar((p_lhs).g, (p_rhs).g)) && \ - (hash_compare_scalar((p_lhs).b, (p_rhs).b)) && \ - (hash_compare_scalar((p_lhs).a, (p_rhs).a)) + (((p_lhs) == (p_rhs)) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs))) + +#define hash_compare_vector2(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).x, (p_rhs).x) && \ + hash_compare_scalar((p_lhs).y, (p_rhs).y)) + +#define hash_compare_vector3(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).x, (p_rhs).x) && \ + hash_compare_scalar((p_lhs).y, (p_rhs).y) && \ + hash_compare_scalar((p_lhs).z, (p_rhs).z)) + +#define hash_compare_vector4(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).x, (p_rhs).x) && \ + hash_compare_scalar((p_lhs).y, (p_rhs).y) && \ + hash_compare_scalar((p_lhs).z, (p_rhs).z) && \ + hash_compare_scalar((p_lhs).w, (p_rhs).w)) + +#define hash_compare_quaternion(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).x, (p_rhs).x) && \ + hash_compare_scalar((p_lhs).y, (p_rhs).y) && \ + hash_compare_scalar((p_lhs).z, (p_rhs).z) && \ + hash_compare_scalar((p_lhs).w, (p_rhs).w)) + +#define hash_compare_color(p_lhs, p_rhs) \ + (hash_compare_scalar((p_lhs).r, (p_rhs).r) && \ + hash_compare_scalar((p_lhs).g, (p_rhs).g) && \ + hash_compare_scalar((p_lhs).b, (p_rhs).b) && \ + hash_compare_scalar((p_lhs).a, (p_rhs).a)) #define hash_compare_packed_array(p_lhs, p_rhs, p_type, p_compare_func) \ const Vector<p_type> &l = PackedArrayRef<p_type>::get_array(p_lhs); \ @@ -3323,8 +3324,8 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const const Rect2 *l = reinterpret_cast<const Rect2 *>(_data._mem); const Rect2 *r = reinterpret_cast<const Rect2 *>(p_variant._data._mem); - return (hash_compare_vector2(l->position, r->position)) && - (hash_compare_vector2(l->size, r->size)); + return hash_compare_vector2(l->position, r->position) && + hash_compare_vector2(l->size, r->size); } break; case RECT2I: { const Rect2i *l = reinterpret_cast<const Rect2i *>(_data._mem); @@ -3338,7 +3339,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const Transform2D *r = p_variant._data._transform2d; for (int i = 0; i < 3; i++) { - if (!(hash_compare_vector2(l->columns[i], r->columns[i]))) { + if (!hash_compare_vector2(l->columns[i], r->columns[i])) { return false; } } @@ -3375,16 +3376,16 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const const Plane *l = reinterpret_cast<const Plane *>(_data._mem); const Plane *r = reinterpret_cast<const Plane *>(p_variant._data._mem); - return (hash_compare_vector3(l->normal, r->normal)) && - (hash_compare_scalar(l->d, r->d)); + return hash_compare_vector3(l->normal, r->normal) && + hash_compare_scalar(l->d, r->d); } break; case AABB: { const ::AABB *l = _data._aabb; const ::AABB *r = p_variant._data._aabb; - return (hash_compare_vector3(l->position, r->position) && - (hash_compare_vector3(l->size, r->size))); + return hash_compare_vector3(l->position, r->position) && + hash_compare_vector3(l->size, r->size); } break; @@ -3400,7 +3401,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const const Basis *r = p_variant._data._basis; for (int i = 0; i < 3; i++) { - if (!(hash_compare_vector3(l->rows[i], r->rows[i]))) { + if (!hash_compare_vector3(l->rows[i], r->rows[i])) { return false; } } @@ -3413,7 +3414,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const const Transform3D *r = p_variant._data._transform3d; for (int i = 0; i < 3; i++) { - if (!(hash_compare_vector3(l->basis.rows[i], r->basis.rows[i]))) { + if (!hash_compare_vector3(l->basis.rows[i], r->basis.rows[i])) { return false; } } @@ -3425,7 +3426,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const const Projection *r = p_variant._data._projection; for (int i = 0; i < 4; i++) { - if (!(hash_compare_vector4(l->columns[i], r->columns[i]))) { + if (!hash_compare_vector4(l->columns[i], r->columns[i])) { return false; } } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 8a07d509a1..11daf739d2 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2466,7 +2466,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } else if (GDScriptUtilityFunctions::function_exists(function_name)) { MethodInfo function_info = GDScriptUtilityFunctions::get_function_info(function_name); - if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) { + if (!p_is_root && !p_is_await && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) { push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call); } @@ -2513,7 +2513,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } else if (Variant::has_utility_function(function_name)) { MethodInfo function_info = info_from_utility_func(function_name); - if (!p_is_root && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) { + if (!p_is_root && !p_is_await && function_info.return_val.type == Variant::NIL && ((function_info.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) == 0)) { push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", function_name), p_call); } @@ -2659,7 +2659,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a mark_lambda_use_self(); } - if (!p_is_root && return_type.is_hard_type() && return_type.kind == GDScriptParser::DataType::BUILTIN && return_type.builtin_type == Variant::NIL) { + if (!p_is_root && !p_is_await && return_type.is_hard_type() && return_type.kind == GDScriptParser::DataType::BUILTIN && return_type.builtin_type == Variant::NIL) { push_error(vformat(R"*(Cannot get return value of call to "%s()" because it returns "void".)*", p_call->function_name), p_call); } diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 8b3ae17e5f..15a17edb65 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -920,13 +920,23 @@ void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Addres append(index); } +GDScriptCodeGenerator::Address GDScriptByteCodeGenerator::get_call_target(const GDScriptCodeGenerator::Address &p_target) { + if (p_target.mode == Address::NIL) { + uint32_t addr = add_temporary(p_target.type); + pop_temporary(); + return Address(Address::TEMPORARY, addr, p_target.type); + } else { + return p_target; + } +} + void GDScriptByteCodeGenerator::write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) { append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size()); for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } append(p_base); - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_function_name); } @@ -936,7 +946,7 @@ void GDScriptByteCodeGenerator::write_super_call(const Address &p_target, const for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_function_name); } @@ -947,7 +957,7 @@ void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const append(p_arguments[i]); } append(p_base); - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_function_name); } @@ -957,7 +967,7 @@ void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_tar for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_function); } @@ -983,7 +993,7 @@ void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, cons for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(Variant::get_validated_utility_function(p_function)); } else { @@ -991,7 +1001,7 @@ void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, cons for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_function); } @@ -1035,7 +1045,7 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, append(p_arguments[i]); } append(p_base); - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(Variant::get_validated_builtin_method(p_type, p_method)); } @@ -1064,7 +1074,7 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_ for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_type); append(p_method); append(p_arguments.size()); @@ -1085,7 +1095,7 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_ append(p_arguments[i]); } append(Address()); // No base since it's static. - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(Variant::get_validated_builtin_method(p_type, p_method)); } @@ -1101,7 +1111,7 @@ void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(method); append(p_arguments.size()); return; @@ -1114,7 +1124,7 @@ void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, append(p_arguments[i]); } append(p_base); - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_method); } @@ -1178,7 +1188,7 @@ void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, cons append(p_arguments[i]); } append(p_base); - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_method); if (is_ptrcall) { @@ -1194,7 +1204,7 @@ void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const S append(p_arguments[i]); } append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_function_name); } @@ -1205,7 +1215,7 @@ void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, c append(p_arguments[i]); } append(GDScriptFunction::ADDR_SELF); - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_function_name); } @@ -1216,7 +1226,7 @@ void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_targ append(p_arguments[i]); } append(p_base); - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_function_name); } @@ -1227,7 +1237,7 @@ void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFu append(p_captures[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_captures.size()); append(p_function); } @@ -1266,7 +1276,7 @@ void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(Variant::get_validated_constructor(p_type, valid_constructor)); return; @@ -1277,7 +1287,7 @@ void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); append(p_type); } @@ -1287,7 +1297,7 @@ void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, c for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size()); } @@ -1296,7 +1306,7 @@ void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_tar for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); if (p_element_type.script_type) { Variant script_type = Ref<Script>(p_element_type.script_type); int addr = get_constant_pos(script_type); @@ -1315,7 +1325,7 @@ void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_targ for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(p_target); + append(get_call_target(p_target)); append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments. } diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index ba4847813f..258b9fb0c2 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -309,6 +309,8 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { } } + Address get_call_target(const Address &p_target); + int address_of(const Address &p_address) { switch (p_address.mode) { case Address::SELF: diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 2d36692c3c..640d7dca2f 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -520,10 +520,12 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code case GDScriptParser::Node::CALL: { const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression); GDScriptDataType type = _gdtype_from_datatype(call->get_datatype(), codegen.script); - GDScriptCodeGenerator::Address result = codegen.add_temporary(type); - GDScriptCodeGenerator::Address nil = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL); - - GDScriptCodeGenerator::Address return_addr = p_root ? nil : result; + GDScriptCodeGenerator::Address result; + if (p_root) { + result = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL); + } else { + result = codegen.add_temporary(type); + } Vector<GDScriptCodeGenerator::Address> arguments; for (int i = 0; i < call->arguments.size(); i++) { @@ -538,20 +540,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // Construct a built-in type. Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name); - gen->write_construct(return_addr, vtype, arguments); + gen->write_construct(result, vtype, arguments); } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) { // Variant utility function. - gen->write_call_utility(return_addr, call->function_name, arguments); + gen->write_call_utility(result, call->function_name, arguments); } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) { // GDScript utility function. - gen->write_call_gdscript_utility(return_addr, GDScriptUtilityFunctions::get_function(call->function_name), arguments); + gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments); } else { // Regular function. const GDScriptParser::ExpressionNode *callee = call->callee; if (call->is_super) { // Super call. - gen->write_super_call(return_addr, call->function_name, arguments); + gen->write_super_call(result, call->function_name, arguments); } else { if (callee->type == GDScriptParser::Node::IDENTIFIER) { // Self function call. @@ -563,24 +565,24 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (_have_exact_arguments(method, arguments)) { // Exact arguments, use ptrcall. - gen->write_call_ptrcall(return_addr, self, method, arguments); + gen->write_call_ptrcall(result, self, method, arguments); } else { // Not exact arguments, but still can use method bind call. - gen->write_call_method_bind(return_addr, self, method, arguments); + gen->write_call_method_bind(result, self, method, arguments); } } else if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") { GDScriptCodeGenerator::Address self; self.mode = GDScriptCodeGenerator::Address::CLASS; if (within_await) { - gen->write_call_async(return_addr, self, call->function_name, arguments); + gen->write_call_async(result, self, call->function_name, arguments); } else { - gen->write_call(return_addr, self, call->function_name, arguments); + gen->write_call(result, self, call->function_name, arguments); } } else { if (within_await) { - gen->write_call_self_async(return_addr, call->function_name, arguments); + gen->write_call_self_async(result, call->function_name, arguments); } else { - gen->write_call_self(return_addr, call->function_name, arguments); + gen->write_call_self(result, call->function_name, arguments); } } } else if (callee->type == GDScriptParser::Node::SUBSCRIPT) { @@ -589,18 +591,18 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (subscript->is_attribute) { // May be static built-in method call. if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) { - gen->write_call_builtin_type_static(return_addr, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments); + gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments); } else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") && ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) { // It's a static native method call. - gen->write_call_native_static(return_addr, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments); + gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments); } else { GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); if (r_error) { return GDScriptCodeGenerator::Address(); } if (within_await) { - gen->write_call_async(return_addr, base, call->function_name, arguments); + gen->write_call_async(result, base, call->function_name, arguments); } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) { // Native method, use faster path. StringName class_name; @@ -613,18 +615,18 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code MethodBind *method = ClassDB::get_method(class_name, call->function_name); if (_have_exact_arguments(method, arguments)) { // Exact arguments, use ptrcall. - gen->write_call_ptrcall(return_addr, base, method, arguments); + gen->write_call_ptrcall(result, base, method, arguments); } else { // Not exact arguments, but still can use method bind call. - gen->write_call_method_bind(return_addr, base, method, arguments); + gen->write_call_method_bind(result, base, method, arguments); } } else { - gen->write_call(return_addr, base, call->function_name, arguments); + gen->write_call(result, base, call->function_name, arguments); } } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { - gen->write_call_builtin_type(return_addr, base, base.type.builtin_type, call->function_name, arguments); + gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); } else { - gen->write_call(return_addr, base, call->function_name, arguments); + gen->write_call(result, base, call->function_name, arguments); } if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { gen->pop_temporary(); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 6107bb37c8..add8a02e55 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -1799,24 +1799,29 @@ GDScriptParser::AssertNode *GDScriptParser::parse_assert() { // TODO: Add assert message. AssertNode *assert = alloc_node<AssertNode>(); + push_multiline(true); consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after "assert".)"); + assert->condition = parse_expression(false); if (assert->condition == nullptr) { push_error("Expected expression to assert."); + pop_multiline(); complete_extents(assert); return nullptr; } - if (match(GDScriptTokenizer::Token::COMMA)) { - // Error message. + if (match(GDScriptTokenizer::Token::COMMA) && !check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE)) { assert->message = parse_expression(false); if (assert->message == nullptr) { push_error(R"(Expected error message for assert after ",".)"); + pop_multiline(); complete_extents(assert); return nullptr; } + match(GDScriptTokenizer::Token::COMMA); } + pop_multiline(); consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after assert expression.)*"); complete_extents(assert); diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_assert.gd b/modules/gdscript/tests/scripts/parser/features/multiline_assert.gd new file mode 100644 index 0000000000..8c699c604d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_assert.gd @@ -0,0 +1,24 @@ +func test(): + var x := 5 + + assert(x > 0) + assert(x > 0,) + assert(x > 0, 'message') + assert(x > 0, 'message',) + + assert( + x > 0 + ) + assert( + x > 0, + ) + assert( + x > 0, + 'message' + ) + assert( + x > 0, + 'message', + ) + + print('OK') diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_assert.out b/modules/gdscript/tests/scripts/parser/features/multiline_assert.out new file mode 100644 index 0000000000..1ccb591560 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/multiline_assert.out @@ -0,0 +1,2 @@ +GDTEST_OK +OK diff --git a/modules/gdscript/tests/scripts/runtime/features/await_on_void.gd b/modules/gdscript/tests/scripts/runtime/features/await_on_void.gd new file mode 100644 index 0000000000..46b9fbc951 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/await_on_void.gd @@ -0,0 +1,7 @@ +func wait() -> void: + pass + +func test(): + @warning_ignore(redundant_await) + await wait() + print("end") diff --git a/modules/gdscript/tests/scripts/runtime/features/await_on_void.out b/modules/gdscript/tests/scripts/runtime/features/await_on_void.out new file mode 100644 index 0000000000..5bc3dcf2db --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/await_on_void.out @@ -0,0 +1,2 @@ +GDTEST_OK +end diff --git a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd b/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd new file mode 100644 index 0000000000..cc34e71b01 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd @@ -0,0 +1,45 @@ +# https://github.com/godotengine/godot/issues/70964 + +func test(): + test_construct(0, false) + test_utility(0, false) + test_builtin_call(Vector2.UP, false) + test_builtin_call_validated(Vector2.UP, false) + test_object_call(RefCounted.new(), false) + test_object_call_method_bind(Resource.new(), false) + test_object_call_ptrcall(RefCounted.new(), false) + + print("end") + +func test_construct(v, f): + Vector2(v, v) # Built-in type construct. + assert(not f) # Test unary operator reading from `nil`. + +func test_utility(v, f): + abs(v) # Utility function. + assert(not f) # Test unary operator reading from `nil`. + +func test_builtin_call(v, f): + @warning_ignore(unsafe_method_access) + v.angle() # Built-in method call. + assert(not f) # Test unary operator reading from `nil`. + +func test_builtin_call_validated(v: Vector2, f): + @warning_ignore(return_value_discarded) + v.abs() # Built-in method call validated. + assert(not f) # Test unary operator reading from `nil`. + +func test_object_call(v, f): + @warning_ignore(unsafe_method_access) + v.get_reference_count() # Native type method call. + assert(not f) # Test unary operator reading from `nil`. + +func test_object_call_method_bind(v: Resource, f): + @warning_ignore(return_value_discarded) + v.duplicate() # Native type method call with MethodBind. + assert(not f) # Test unary operator reading from `nil`. + +func test_object_call_ptrcall(v: RefCounted, f): + @warning_ignore(return_value_discarded) + v.get_reference_count() # Native type method call with ptrcall. + assert(not f) # Test unary operator reading from `nil`. diff --git a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out b/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out new file mode 100644 index 0000000000..5bc3dcf2db --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out @@ -0,0 +1,2 @@ +GDTEST_OK +end diff --git a/platform/ios/device_metrics.m b/platform/ios/device_metrics.m index b51f45c602..d6f5ec8e42 100644 --- a/platform/ios/device_metrics.m +++ b/platform/ios/device_metrics.m @@ -35,117 +35,159 @@ + (NSDictionary *)dpiList { return @{ @[ - @"iPad1,1", - @"iPad2,1", - @"iPad2,2", - @"iPad2,3", - @"iPad2,4", + @"iPad1,1", // iPad 1th Gen + @"iPad1,2", // iPad 1th Gen (3G) + @"iPad2,1", // iPad 2nd Gen + @"iPad2,2", // iPad 2nd Gen (GSM) + @"iPad2,3", // iPad 2nd Gen (CDMA) + @"iPad2,4", // iPad 2nd Gen ] : @132, @[ - @"iPhone1,1", - @"iPhone1,2", - @"iPhone2,1", - @"iPad2,5", - @"iPad2,6", - @"iPad2,7", - @"iPod1,1", - @"iPod2,1", - @"iPod3,1", + @"iPhone1,1", // iPhone 1st Gen + @"iPhone1,2", // iPhone 3G + @"iPhone2,1", // iPhone 3GS + @"iPad2,5", // iPad mini + @"iPad2,6", // iPad mini (GSM+LTE) + @"iPad2,7", // iPad mini (CDMA+LTE) + @"iPod1,1", // iPod 1st Gen + @"iPod2,1", // iPod 2nd Gen + @"iPod3,1", // iPod 3rd Gen ] : @163, @[ - @"iPad3,1", - @"iPad3,2", - @"iPad3,3", - @"iPad3,4", - @"iPad3,5", - @"iPad3,6", - @"iPad4,1", - @"iPad4,2", - @"iPad4,3", - @"iPad5,3", - @"iPad5,4", - @"iPad6,3", - @"iPad6,4", - @"iPad6,7", - @"iPad6,8", - @"iPad6,11", - @"iPad6,12", - @"iPad7,1", - @"iPad7,2", - @"iPad7,3", - @"iPad7,4", - @"iPad7,5", - @"iPad7,6", - @"iPad7,11", - @"iPad7,12", - @"iPad8,1", - @"iPad8,2", - @"iPad8,3", - @"iPad8,4", - @"iPad8,5", - @"iPad8,6", - @"iPad8,7", - @"iPad8,8", - @"iPad8,9", - @"iPad8,10", - @"iPad8,11", - @"iPad8,12", - @"iPad11,3", - @"iPad11,4", + @"iPad3,1", // iPad 3rd Gen + @"iPad3,2", // iPad 3rd Gen (CDMA) + @"iPad3,3", // iPad 3rd Gen (GSM) + @"iPad3,4", // iPad 4th Gen + @"iPad3,5", // iPad 4th Gen (GSM+LTE) + @"iPad3,6", // iPad 4th Gen (CDMA+LTE) + @"iPad4,1", // iPad Air (WiFi) + @"iPad4,2", // iPad Air (GSM+CDMA) + @"iPad4,3", // iPad Air (China) + @"iPad4,7", // iPad mini 3 (WiFi) + @"iPad4,8", // iPad mini 3 (GSM+CDMA) + @"iPad4,9", // iPad Mini 3 (China) + @"iPad6,3", // iPad Pro (9.7 inch, WiFi) + @"iPad6,4", // iPad Pro (9.7 inch, WiFi+LTE) + @"iPad6,7", // iPad Pro (12.9 inch, WiFi) + @"iPad6,8", // iPad Pro (12.9 inch, WiFi+LTE) + @"iPad6,11", // iPad 5th Gen (2017) + @"iPad6,12", // iPad 5th Gen (2017) + @"iPad7,1", // iPad Pro 2nd Gen (WiFi) + @"iPad7,2", // iPad Pro 2nd Gen (WiFi+Cellular) + @"iPad7,3", // iPad Pro 10.5-inch 2nd Gen + @"iPad7,4", // iPad Pro 10.5-inch 2nd Gen + @"iPad7,5", // iPad 6th Gen (WiFi) + @"iPad7,6", // iPad 6th Gen (WiFi+Cellular) + @"iPad7,11", // iPad 7th Gen 10.2-inch (WiFi) + @"iPad7,12", // iPad 7th Gen 10.2-inch (WiFi+Cellular) + @"iPad8,1", // iPad Pro 11 inch 3rd Gen (WiFi) + @"iPad8,2", // iPad Pro 11 inch 3rd Gen (1TB, WiFi) + @"iPad8,3", // iPad Pro 11 inch 3rd Gen (WiFi+Cellular) + @"iPad8,4", // iPad Pro 11 inch 3rd Gen (1TB, WiFi+Cellular) + @"iPad8,5", // iPad Pro 12.9 inch 3rd Gen (WiFi) + @"iPad8,6", // iPad Pro 12.9 inch 3rd Gen (1TB, WiFi) + @"iPad8,7", // iPad Pro 12.9 inch 3rd Gen (WiFi+Cellular) + @"iPad8,8", // iPad Pro 12.9 inch 3rd Gen (1TB, WiFi+Cellular) + @"iPad8,9", // iPad Pro 11 inch 4th Gen (WiFi) + @"iPad8,10", // iPad Pro 11 inch 4th Gen (WiFi+Cellular) + @"iPad8,11", // iPad Pro 12.9 inch 4th Gen (WiFi) + @"iPad8,12", // iPad Pro 12.9 inch 4th Gen (WiFi+Cellular) + @"iPad11,3", // iPad Air 3rd Gen (WiFi) + @"iPad11,4", // iPad Air 3rd Gen + @"iPad11,6", // iPad 8th Gen (WiFi) + @"iPad11,7", // iPad 8th Gen (WiFi+Cellular) + @"iPad12,1", // iPad 9th Gen (WiFi) + @"iPad12,2", // iPad 9th Gen (WiFi+Cellular) + @"iPad13,1", // iPad Air 4th Gen (WiFi) + @"iPad13,2", // iPad Air 4th Gen (WiFi+Cellular) + @"iPad13,4", // iPad Pro 11 inch 5th Gen + @"iPad13,5", // iPad Pro 11 inch 5th Gen + @"iPad13,6", // iPad Pro 11 inch 5th Gen + @"iPad13,7", // iPad Pro 11 inch 5th Gen + @"iPad13,8", // iPad Pro 12.9 inch 5th Gen + @"iPad13,9", // iPad Pro 12.9 inch 5th Gen + @"iPad13,10", // iPad Pro 12.9 inch 5th Gen + @"iPad13,11", // iPad Pro 12.9 inch 5th Gen + @"iPad13,16", // iPad Air 5th Gen (WiFi) + @"iPad13,17", // iPad Air 5th Gen (WiFi+Cellular) + @"iPad13,18", // iPad 10th Gen + @"iPad13,19", // iPad 10th Gen + @"iPad14,3", // iPad Pro 11 inch 6th Gen + @"iPad14,4", // iPad Pro 11 inch 6th Gen + @"iPad14,5", // iPad Pro 12.9 inch 6th Gen + @"iPad14,6", // iPad Pro 12.9 inch 6th Gen ] : @264, @[ - @"iPhone3,1", - @"iPhone3,2", - @"iPhone3,3", - @"iPhone4,1", - @"iPhone5,1", - @"iPhone5,2", - @"iPhone5,3", - @"iPhone5,4", - @"iPhone6,1", - @"iPhone6,2", - @"iPhone7,2", - @"iPhone8,1", - @"iPhone8,4", - @"iPhone9,1", - @"iPhone9,3", - @"iPhone10,1", - @"iPhone10,4", - @"iPhone11,8", - @"iPhone12,1", - @"iPhone12,8", - @"iPad4,4", - @"iPad4,5", - @"iPad4,6", - @"iPad4,7", - @"iPad4,8", - @"iPad4,9", - @"iPad5,1", - @"iPad5,2", - @"iPad11,1", - @"iPad11,2", - @"iPod4,1", - @"iPod5,1", - @"iPod7,1", - @"iPod9,1", + @"iPhone3,1", // iPhone 4 + @"iPhone3,2", // iPhone 4 (GSM) + @"iPhone3,3", // iPhone 4 (CDMA) + @"iPhone4,1", // iPhone 4S + @"iPhone5,1", // iPhone 5 (GSM) + @"iPhone5,2", // iPhone 5 (GSM+CDMA) + @"iPhone5,3", // iPhone 5C (GSM) + @"iPhone5,4", // iPhone 5C (Global) + @"iPhone6,1", // iPhone 5S (GSM) + @"iPhone6,2", // iPhone 5S (Global) + @"iPhone7,2", // iPhone 6 + @"iPhone8,1", // iPhone 6s + @"iPhone8,4", // iPhone SE (GSM) + @"iPhone9,1", // iPhone 7 + @"iPhone9,3", // iPhone 7 + @"iPhone10,1", // iPhone 8 + @"iPhone10,4", // iPhone 8 + @"iPhone11,8", // iPhone XR + @"iPhone12,1", // iPhone 11 + @"iPhone12,8", // iPhone SE 2nd gen + @"iPhone14,6", // iPhone SE 3rd gen + @"iPad4,4", // iPad mini Retina (WiFi) + @"iPad4,5", // iPad mini Retina (GSM+CDMA) + @"iPad4,6", // iPad mini Retina (China) + @"iPad5,1", // iPad mini 4th Gen (WiFi) + @"iPad5,2", // iPad mini 4th Gen + @"iPad5,3", // iPad Air 2 (WiFi) + @"iPad5,4", // iPad Air 2 + @"iPad11,1", // iPad mini 5th Gen (WiFi) + @"iPad11,2", // iPad mini 5th Gen + @"iPad14,1", // iPad mini 6th Gen (WiFi) + @"iPad14,2", // iPad mini 6th Gen + @"iPod4,1", // iPod 4th Gen + @"iPod5,1", // iPod 5th Gen + @"iPod7,1", // iPod 6th Gen + @"iPod9,1", // iPod 7th Gen ] : @326, @[ - @"iPhone7,1", - @"iPhone8,2", - @"iPhone9,2", - @"iPhone9,4", - @"iPhone10,2", - @"iPhone10,5", + @"iPhone7,1", // iPhone 6 Plus + @"iPhone8,2", // iPhone 6s Plus + @"iPhone9,2", // iPhone 7 Plus + @"iPhone9,4", // iPhone 7 Plus + @"iPhone10,2", // iPhone 8 Plus + @"iPhone10,5", // iPhone 8 Plus ] : @401, @[ - @"iPhone10,3", - @"iPhone10,6", - @"iPhone11,2", - @"iPhone11,4", - @"iPhone11,6", - @"iPhone12,3", - @"iPhone12,5", + @"iPhone10,3", // iPhone X Global + @"iPhone10,6", // iPhone X GSM + @"iPhone11,2", // iPhone XS + @"iPhone11,4", // iPhone XS Max + @"iPhone11,6", // iPhone XS Max Global + @"iPhone12,3", // iPhone 11 Pro + @"iPhone12,5", // iPhone 11 Pro Max + @"iPhone13,4", // iPhone 12 Pro Max + @"iPhone14,3", // iPhone 13 Pro Max + @"iPhone14,8", // iPhone 14 Plus ] : @458, + @[ + @"iPhone13,2", // iPhone 12 + @"iPhone13,3", // iPhone 12 Pro + @"iPhone14,2", // iPhone 13 Pro + @"iPhone14,5", // iPhone 13 + @"iPhone14,7", // iPhone 14 + @"iPhone15,2", // iPhone 14 Pro + @"iPhone15,3", // iPhone 14 Pro Max + ] : @460, + @[ + @"iPhone13,1", // iPhone 12 Mini + @"iPhone14,4", // iPhone 13 Mini + ] : @476 }; } |