diff --git a/src/filters/exceptions.ml b/src/filters/exceptions.ml index fa4b0182928..d092e890d7d 100644 --- a/src/filters/exceptions.ml +++ b/src/filters/exceptions.ml @@ -480,9 +480,11 @@ let catch_native ctx catches t p = ) (* Haxe-specific wildcard catches should go to if-fest because they need additional handling *) | (v,_) :: _ when is_haxe_wildcard_catch ctx v.v_type -> - (match handle_as_value_exception with - | [] -> + (match handle_as_value_exception, value_exception_catch with + | [], None -> catches_to_ifs ctx catches t p + | [], Some catch -> + catches_to_ifs ctx [catch] t p | _ -> catches_as_value_exception ctx handle_as_value_exception None t p :: catches_to_ifs ctx catches t p diff --git a/src/generators/gencpp.ml b/src/generators/gencpp.ml index 48cbb065e39..e417bbbb718 100644 --- a/src/generators/gencpp.ml +++ b/src/generators/gencpp.ml @@ -393,7 +393,12 @@ let keyword_remap name = | "HX_" | "HXLINE" | "HXDLIN" | "NO" | "YES" | "abstract" | "decltype" | "finally" | "nullptr" | "static_assert" - | "struct" -> "_hx_" ^ name + | "struct" | "_Atomic" + | "constexpr" | "consteval" | "constinit" + | "co_await" | "co_return" | "co_yield" + | "alignas" | "alignof" + | "_Alignas" | "_Alignof" + | "requires" -> "_hx_" ^ name | x -> x ;; diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index a6de801d3de..7db70613ea8 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -3329,7 +3329,10 @@ let generate_static ctx c f = let gen_content() = op ctx (OThrow (make_string ctx ("Requires compiling with -D hl-ver=" ^ ver ^ ".0 or higher") null_pos)); in - ignore(make_fun ctx ~gen_content (s_type_path c.cl_path,f.cf_name) (alloc_fid ctx c f) (match f.cf_expr with Some { eexpr = TFunction f } -> f | _ -> abort "Missing function body" f.cf_pos) None None) + (match f.cf_expr with + | Some { eexpr = TFunction fn } -> ignore(make_fun ctx ~gen_content (s_type_path c.cl_path,f.cf_name) (alloc_fid ctx c f) fn None None) + | _ -> if not (Meta.has Meta.NoExpr f.cf_meta) then abort "Missing function body" f.cf_pos) + else add_native "std" f.cf_name | (Meta.HlNative,[] ,_ ) :: _ -> @@ -3337,7 +3340,9 @@ let generate_static ctx c f = | (Meta.HlNative,_ ,p) :: _ -> abort "Invalid @:hlNative decl" p | [] -> - ignore(make_fun ctx (s_type_path c.cl_path,f.cf_name) (alloc_fid ctx c f) (match f.cf_expr with Some { eexpr = TFunction f } -> f | _ -> abort "Missing function body" f.cf_pos) None None) + (match f.cf_expr with + | Some { eexpr = TFunction fn } -> ignore(make_fun ctx (s_type_path c.cl_path,f.cf_name) (alloc_fid ctx c f) fn None None) + | _ -> if not (Meta.has Meta.NoExpr f.cf_meta) then abort "Missing function body" f.cf_pos) | _ :: l -> loop l in diff --git a/src/typing/nullSafety.ml b/src/typing/nullSafety.ml index d411fcb5a95..b0683bce6d7 100644 --- a/src/typing/nullSafety.ml +++ b/src/typing/nullSafety.ml @@ -1041,6 +1041,8 @@ class expr_checker mode immediate_execution report = | TMeta (_, e) -> self#is_nullable_expr e | TThrow _ -> false | TReturn _ -> false + | TContinue -> false + | TBreak -> false | TBinop ((OpAssign | OpAssignOp _), _, right) -> self#is_nullable_expr right | TBlock exprs -> local_safety#block_declared; diff --git a/std/cpp/_std/haxe/Exception.hx b/std/cpp/_std/haxe/Exception.hx index 4c244a7e34d..92fbaf553bd 100644 --- a/std/cpp/_std/haxe/Exception.hx +++ b/std/cpp/_std/haxe/Exception.hx @@ -19,7 +19,10 @@ class Exception { if(Std.isOfType(value, Exception)) { return value; } else { - return new ValueException(value, null, value); + var e = new ValueException(value, null, value); + // Undo automatic __shiftStack() + e.__unshiftStack(); + return e; } } @@ -63,6 +66,12 @@ class Exception { __skipStack++; } + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __unshiftStack():Void { + __skipStack--; + } + function get_message():String { return __exceptionMessage; } diff --git a/std/eval/_std/haxe/Exception.hx b/std/eval/_std/haxe/Exception.hx index 814370e7ac8..48467a04484 100644 --- a/std/eval/_std/haxe/Exception.hx +++ b/std/eval/_std/haxe/Exception.hx @@ -18,7 +18,10 @@ class Exception { if(Std.isOfType(value, Exception)) { return value; } else { - return new ValueException(value, null, value); + var e = new ValueException(value, null, value); + // Undo automatic __shiftStack() + e.__unshiftStack(); + return e; } } @@ -63,6 +66,12 @@ class Exception { __skipStack++; } + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __unshiftStack():Void { + __skipStack--; + } + function get_message():String { return __exceptionMessage; } diff --git a/std/haxe/macro/MacroStringTools.hx b/std/haxe/macro/MacroStringTools.hx index 85e12b9b9a9..bfd422e4eb0 100644 --- a/std/haxe/macro/MacroStringTools.hx +++ b/std/haxe/macro/MacroStringTools.hx @@ -94,6 +94,10 @@ class MacroStringTools { static public function toComplex(path:String):ComplexType { var pack = path.split("."); - return TPath({pack: pack, name: pack.pop(), params: []}); + if(pack.length >= 2 && ~/^[A-Z]/.match(pack[pack.length - 2])) { + return TPath({pack: pack, sub: pack.pop(), name: pack.pop(), params: []}); + } else { + return TPath({pack: pack, name: pack.pop(), params: []}); + } } } diff --git a/std/hl/_std/haxe/Exception.hx b/std/hl/_std/haxe/Exception.hx index 8f3ae5fc734..68734c49586 100644 --- a/std/hl/_std/haxe/Exception.hx +++ b/std/hl/_std/haxe/Exception.hx @@ -18,7 +18,10 @@ class Exception { if(Std.isOfType(value, Exception)) { return value; } else { - return new ValueException(value, null, value); + var e = new ValueException(value, null, value); + // Undo automatic __shiftStack() + e.__unshiftStack(); + return e; } } @@ -62,6 +65,12 @@ class Exception { __skipStack++; } + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __unshiftStack():Void { + __skipStack--; + } + function get_message():String { return __exceptionMessage; } diff --git a/std/hl/_std/haxe/NativeStackTrace.hx b/std/hl/_std/haxe/NativeStackTrace.hx index e7cf077a142..eada6faf0be 100644 --- a/std/hl/_std/haxe/NativeStackTrace.hx +++ b/std/hl/_std/haxe/NativeStackTrace.hx @@ -29,7 +29,7 @@ class NativeStackTrace { var count = callStackRaw(null); var arr = new NativeArray(count); callStackRaw(arr); - return arr; + return arr.sub(1, arr.length - 1); } @:hlNative("std", "exception_stack_raw") diff --git a/std/neko/_std/haxe/Exception.hx b/std/neko/_std/haxe/Exception.hx index 1302231c141..0579eb835ab 100644 --- a/std/neko/_std/haxe/Exception.hx +++ b/std/neko/_std/haxe/Exception.hx @@ -18,7 +18,10 @@ class Exception { if(Std.isOfType(value, Exception)) { return value; } else { - return new ValueException(value, null, value); + var e = new ValueException(value, null, value); + // Undo automatic __shiftStack() + e.__unshiftStack(); + return e; } } @@ -63,6 +66,12 @@ class Exception { __skipStack++; } + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __unshiftStack():Void { + __skipStack--; + } + function get_message():String { return __exceptionMessage; } diff --git a/tests/misc/hl/projects/Issue11196/Issue11196.hx b/tests/misc/hl/projects/Issue11196/Issue11196.hx new file mode 100644 index 00000000000..9126da39de6 --- /dev/null +++ b/tests/misc/hl/projects/Issue11196/Issue11196.hx @@ -0,0 +1,3 @@ +function main() { + var a:hl.I64 = 5; +} \ No newline at end of file diff --git a/tests/misc/hl/projects/Issue11196/compile.hxml b/tests/misc/hl/projects/Issue11196/compile.hxml new file mode 100644 index 00000000000..49a5d4098e6 --- /dev/null +++ b/tests/misc/hl/projects/Issue11196/compile.hxml @@ -0,0 +1,3 @@ +-m Issue11196 +-hl out.hl +-dce no \ No newline at end of file diff --git a/tests/nullsafety/src/cases/TestLoose.hx b/tests/nullsafety/src/cases/TestLoose.hx index 233f9c778d7..704f6521abd 100644 --- a/tests/nullsafety/src/cases/TestLoose.hx +++ b/tests/nullsafety/src/cases/TestLoose.hx @@ -113,4 +113,11 @@ class TestLoose { } shouldFail(if (foo()) {}); } + + static function nullCoal_continue_shouldPass():Void { + for (i in 0...1) { + var i:String = staticVar ?? continue; + var i2:String = staticVar ?? break; + } + } } diff --git a/tests/unit/src/unit/TestExceptions.hx b/tests/unit/src/unit/TestExceptions.hx index 98fd5e13a48..6fb5580af80 100644 --- a/tests/unit/src/unit/TestExceptions.hx +++ b/tests/unit/src/unit/TestExceptions.hx @@ -1,4 +1,4 @@ -package unit; +package unit; import haxe.Exception; import haxe.exceptions.ArgumentException; @@ -235,17 +235,16 @@ class TestExceptions extends Test { public function testExceptionStack() { var data = [ '_without_ throws' => stacksWithoutThrowLevel1(), - '_with_ throws' => stacksWithThrowLevel1() + '_with_ throws' => stacksWithThrowLevel1(), + #if (eval || hl || neko) + 'auto wrapped' => stacksAutoWrappedLevel1() + #end ]; for(label => stacks in data) { Assert.isTrue(stacks.length > 1, '$label: wrong stacks.length'); var expected = null; var lineShift = 0; for(s in stacks) { - // TODO: fix hl vs other targets difference with callstacks - // See https://github.com/HaxeFoundation/haxe/issues/10926 - #if hl @:privateAccess s.asArray().shift(); #end - if(expected == null) { expected = stackItemData(s[0]); } else { @@ -295,6 +294,24 @@ class TestExceptions extends Test { return result; } + #if (eval || hl || neko) + function stacksAutoWrappedLevel1() { + return stacksAutoWrappedLevel2(); + } + + function stacksAutoWrappedLevel2():Array { + @:pure(false) function wrapNativeError(_) return []; + + var result:Array = []; + // It's critical for `testExceptionStack` test to keep the following lines + // order with no additional code in between. + result.push(try throw new Exception('') catch(e:Exception) e.stack); + result.push(try throw "" catch(e:Exception) e.stack); + result.push(try wrapNativeError((null:String).length) catch(e:Exception) e.stack); + return result; + } + #end + function stackItemData(item:StackItem):ItemData { var result:ItemData = {}; switch item { @@ -321,6 +338,16 @@ class TestExceptions extends Test { eq('haxe.Exception', HelperMacros.typeString(try throw new Exception('') catch(e) e)); } + function testCatchValueException() { + try { + throw ""; + } catch(e:ValueException) { + Assert.pass(); + } catch(e) { + Assert.fail(); + } + } + function testNotImplemented() { try { futureFeature(); @@ -374,4 +401,4 @@ class TestExceptions extends Test { } } #end -} \ No newline at end of file +}