diff --git a/sdk/add_on/weakref/weakref.cpp b/sdk/add_on/weakref/weakref.cpp index 385ff7155..7d82a1547 100644 --- a/sdk/add_on/weakref/weakref.cpp +++ b/sdk/add_on/weakref/weakref.cpp @@ -226,7 +226,7 @@ void RegisterScriptWeakRef_Native(asIScriptEngine *engine) r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 ); @@ -242,7 +242,7 @@ void RegisterScriptWeakRef_Native(asIScriptEngine *engine) r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 ); @@ -332,7 +332,7 @@ void RegisterScriptWeakRef_Generic(asIScriptEngine *engine) r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); @@ -348,7 +348,7 @@ void RegisterScriptWeakRef_Generic(asIScriptEngine *engine) r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); diff --git a/sdk/angelscript/source/as_compiler.cpp b/sdk/angelscript/source/as_compiler.cpp index f00be8fc5..1fa38ddde 100644 --- a/sdk/angelscript/source/as_compiler.cpp +++ b/sdk/angelscript/source/as_compiler.cpp @@ -1513,7 +1513,8 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, as else if( ctx->type.dataType.IsNullHandle() ) { // Make sure the argument type can support handles (or is itself a handle) - if( !dt.SupportHandles() && !dt.IsObjectHandle() ) + // Don't allow null handle to be converted to an object type of ASHANDLE here, that would require more logic to call the constructor (which should be handled in ImplicitConversion) + if( (!dt.SupportHandles() && !dt.IsObjectHandle()) || (dt.GetTypeInfo() && (dt.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) ) { asCString str; str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf()); @@ -7173,12 +7174,23 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDat asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode); // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly - // construct the object through any of the available constructors + // construct the object through any of the available constructors (except those marked as explicit) if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct ) { asCArray funcs; funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors; + // Don't allow use of explicit constructors/factories in implicit conversions + if (convType == asIC_IMPLICIT_CONV) + { + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction* desc = builder->GetFunctionDescription(funcs[n]); + if (desc->IsExplicit()) + funcs.RemoveIndex(n--); + } + } + asCArray args; args.PushLast(ctx); diff --git a/sdk/docs/articles/changes2.html b/sdk/docs/articles/changes2.html index 3424f1902..eb8979a5b 100644 --- a/sdk/docs/articles/changes2.html +++ b/sdk/docs/articles/changes2.html @@ -15,7 +15,7 @@

AngelScript Change Log

-

Version 2.35.1 WIP - 2021/07/04

+

Version 2.35.1 WIP - 2021/07/19

  • Bug fixes @@ -36,6 +36,7 @@

    Version 2.35.1 WIP - 2021/07/04

  • Fixed invalid bytecode sequence in initialization lists with value types whose opAssign returns void (Thanks jiandingzhe)
  • Fixed registering asBEHAVE_LIST_CONSTRUCT on value type templates (Thanks Suedwest)
  • Fixed compiler error in as_symboltable.h on GCC 11 (Thanks shirubax) +
  • Compiler no longer silently accepts implicit conversion from null handle to object type registered with ASHANDLE if there is no matching implicit constructor (Thanks Patrick Jeeves)
  • Library
      @@ -69,6 +70,7 @@

      Version 2.35.1 WIP - 2021/07/04

    • Fixed the samples concurrent and events on Linux (Thanks Dantrell B)
    • Fixed WRAP_MFN on gnuc when used within templated functions (Thanks vballDrummer)
    • Fixed issue in array::sort with callback that could cause objects in the array to be destroyed by gc (Thanks Miss) +
    • weakref now has its constructor that takes a handle marked as explicit
  • Project
      diff --git a/sdk/docs/doxygen/source/doc_script_stdlib.h b/sdk/docs/doxygen/source/doc_script_stdlib.h index 059024098..f86b13740 100644 --- a/sdk/docs/doxygen/source/doc_script_stdlib.h +++ b/sdk/docs/doxygen/source/doc_script_stdlib.h @@ -637,7 +637,12 @@ can be used in place of the handle where the reference to the object is needed b \section doc_datatypes_weakref_addon Supporting weakref object +\subsection doc_datatypes_weakref_addon_construct Constructors +weakref()
      +weakref(T@) explicit
      +const_weakref()
      +const_weakref(const T@) explicit
      \subsection doc_datatypes_weakref_addon_ops Operators diff --git a/sdk/tests/test_feature/source/test_addon_weakref.cpp b/sdk/tests/test_feature/source/test_addon_weakref.cpp index 2e07a4c5d..1a1fd2c32 100644 --- a/sdk/tests/test_feature/source/test_addon_weakref.cpp +++ b/sdk/tests/test_feature/source/test_addon_weakref.cpp @@ -70,6 +70,39 @@ bool Test() CBufferedOutStream bout; asIScriptEngine *engine; + // Test value-assigning null to the weakref + // Reported by Patrick Jeeves + { + engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); + engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); + bout.buffer = ""; + RegisterScriptWeakRef(engine); + engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); + + const char* script = + "class GameObject {} \n" + "weakref m_connect; \n" + "void main() \n" + "{ \n" + " m_connect = null; \n" + "} \n"; + + asIScriptModule* mod = engine->GetModule("test", asGM_ALWAYS_CREATE); + mod->AddScriptSection(TESTNAME, script); + r = mod->Build(); + if (r >= 0) + TEST_FAILED; + + if (bout.buffer != "Test_Addon_WeakRef (3, 1) : Info : Compiling void main()\n" + "Test_Addon_WeakRef (5, 14) : Error : Can't implicitly convert from '' to 'weakref&'.\n") + { + PRINTF("%s", bout.buffer.c_str()); + TEST_FAILED; + } + + engine->Release(); + } + // Ordinary tests { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); @@ -130,7 +163,7 @@ bool Test() "class Foo {} \n" "void main() \n" "{ \n" - " weakref a = Foo(); \n" + " weakref @a = Foo(); \n" " weakref b; \n" " b = a; \n" " assert( a.get() is b.get() ); \n" @@ -153,6 +186,29 @@ bool Test() TEST_FAILED; } + // It is not allowed to do a value assign directly to the weakref on declaration + bout.buffer = ""; + mod->Discard(); + mod = engine->GetModule("test", asGM_ALWAYS_CREATE); + mod->AddScriptSection("test", + "class Foo {} \n" + "void main() \n" + "{ \n" + " weakref a = Foo(); \n" + "} \n" + ); + r = mod->Build(); + if (r >= 0) + TEST_FAILED; + + if (bout.buffer != "test (2, 1) : Info : Compiling void main()\n" + "test (4, 20) : Error : Can't implicitly convert from 'Foo@&' to 'weakref'.\n") + { + PRINTF("%s", bout.buffer.c_str()); + TEST_FAILED; + } + + engine->ShutDownAndRelease(); }