{"action":"created","issue":{"url":"https://api.github.com/repos/ldc-developers/ldc/issues/1656","repository_url":"https://api.github.com/repos/ldc-developers/ldc","labels_url":"https://api.github.com/repos/ldc-developers/ldc/issues/1656/labels{/name}","comments_url":"https://api.github.com/repos/ldc-developers/ldc/issues/1656/comments","events_url":"https://api.github.com/repos/ldc-developers/ldc/issues/1656/events","html_url":"https://github.com/ldc-developers/ldc/pull/1656","id":168393924,"number":1656,"title":"WIP: -release: Propagate \"nothrow\" to LLVM IR (#1202 follow-up)","user":{"login":"kinke","id":1889215,"avatar_url":"https://avatars.githubusercontent.com/u/1889215?v=3","gravatar_id":"","url":"https://api.github.com/users/kinke","html_url":"https://github.com/kinke","followers_url":"https://api.github.com/users/kinke/followers","following_url":"https://api.github.com/users/kinke/following{/other_user}","gists_url":"https://api.github.com/users/kinke/gists{/gist_id}","starred_url":"https://api.github.com/users/kinke/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kinke/subscriptions","organizations_url":"https://api.github.com/users/kinke/orgs","repos_url":"https://api.github.com/users/kinke/repos","events_url":"https://api.github.com/users/kinke/events{/privacy}","received_events_url":"https://api.github.com/users/kinke/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":4,"created_at":"2016-07-29T19:12:10Z","updated_at":"2016-07-30T10:59:33Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/ldc-developers/ldc/pulls/1656","html_url":"https://github.com/ldc-developers/ldc/pull/1656","diff_url":"https://github.com/ldc-developers/ldc/pull/1656.diff","patch_url":"https://github.com/ldc-developers/ldc/pull/1656.patch"},"body":"This small change has a huge impact, especially when decorating destructors with nothrow.\r\n\r\nnothrow functions will always be called (not invoked) from modules compiled with `-release`. If the nothrow callee throws an Error, the Error cannot be caught by the caller anymore, and it won't run any clean-ups during unwind.\r\n\r\nInside modules with enabled assertions, nothrow callees are still invoked, so the caller may catch the Error (needed for stuff like `assertThrown!AssertError()`) and cleans up properly.\r\n\r\nnothrow functions still throw any errors the regular way via _d_throw_exception(), regardless of compiling the containing module via `-release` or not. Mixing debug and release modules for linking should be\r\npossible - but Errors thrown by nothrow callees will only be catchable in debug modules, and during unwind, only frames of functions defined in debug modules will run their clean-ups. The latter could be problematic under certain circumstances, but it would at least only matter after an Error after all."},"comment":{"url":"https://api.github.com/repos/ldc-developers/ldc/issues/comments/236359182","html_url":"https://github.com/ldc-developers/ldc/pull/1656#issuecomment-236359182","issue_url":"https://api.github.com/repos/ldc-developers/ldc/issues/1656","id":236359182,"user":{"login":"kinke","id":1889215,"avatar_url":"https://avatars.githubusercontent.com/u/1889215?v=3","gravatar_id":"","url":"https://api.github.com/users/kinke","html_url":"https://github.com/kinke","followers_url":"https://api.github.com/users/kinke/followers","following_url":"https://api.github.com/users/kinke/following{/other_user}","gists_url":"https://api.github.com/users/kinke/gists{/gist_id}","starred_url":"https://api.github.com/users/kinke/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kinke/subscriptions","organizations_url":"https://api.github.com/users/kinke/orgs","repos_url":"https://api.github.com/users/kinke/repos","events_url":"https://api.github.com/users/kinke/events{/privacy}","received_events_url":"https://api.github.com/users/kinke/received_events","type":"User","site_admin":false},"created_at":"2016-07-30T10:59:33Z","updated_at":"2016-07-30T10:59:33Z","body":"This front-end optimization apparently quickly isn't applied anymore:\r\n```D\r\nstruct S\r\n{\r\n    ~this() nothrow {}\r\n    void foo() nothrow { throw new Error(\"foo\"); }\r\n}\r\n\r\nstruct Throwing\r\n{\r\n    ~this() {}\r\n    void bar() { throw new Exception(\"bar\"); }\r\n}\r\n\r\nvoid main()\r\n{\r\n    Throwing t;\r\n\r\n    S a;\r\n    a.foo();\r\n    t.bar();\r\n\r\n    {\r\n        S b;\r\n        t.bar();\r\n        b.foo();\r\n\r\n        S().foo();\r\n    }\r\n}\r\n```\r\n\r\nRelease:\r\n```LL\r\ndefine i32 @_Dmain({ i64, { i64, i8* }* } %unnamed) #4 comdat personality i32 (i8*, i8*, i8*, i8*)* @__CxxFrameHandler3 {\r\n  %t = alloca %nothrow.Throwing, align 1          ; [#uses = 5, size/byte = 1]\r\n  %a = alloca %nothrow.S, align 1                 ; [#uses = 4, size/byte = 1]\r\n  %b = alloca %nothrow.S, align 1                 ; [#uses = 4, size/byte = 1]\r\n  %__slS54 = alloca %nothrow.S, align 1           ; [#uses = 3, size/byte = 1]\r\n  %1 = bitcast %nothrow.Throwing* %t to i8*       ; [#uses = 1]\r\n  call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 1, i32 1, i1 false)\r\n  %2 = bitcast %nothrow.S* %a to i8*              ; [#uses = 1]\r\n  call void @llvm.memset.p0i8.i64(i8* %2, i8 0, i64 1, i32 1, i1 false)\r\n  call void @_D7nothrow1S3fooMFNbZv(%nothrow.S* nonnull %a) #0\r\n  invoke void @_D7nothrow8Throwing3barMFZv(%nothrow.Throwing* nonnull %t) #4\r\n          to label %postinvoke unwind label %cleanuppad3\r\n\r\nfinally:                                          ; preds = %try.success11\r\n  call void @_D7nothrow8Throwing6__dtorMFZv(%nothrow.Throwing* nonnull %t) #4\r\n  br label %try.success12\r\n\r\nfinally1:                                         ; preds = %try.success\r\n  call void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %a) #0\r\n  br label %try.success11\r\n\r\ncleanuppad:                                       ; preds = %cleanupret4\r\n  %3 = cleanuppad within none []                  ; [#uses = 4]\r\n  %4 = call i1 @_d_enter_cleanup(i8* null) [ \"funclet\"(token %3) ] ; [#uses = 1]\r\n  br i1 %4, label %finally2, label %cleanupret\r\n\r\nfinally2:                                         ; preds = %cleanuppad\r\n  call void @_D7nothrow8Throwing6__dtorMFZv(%nothrow.Throwing* nonnull %t) #4 [ \"funclet\"(token %3) ]\r\n  br label %cleanupret\r\n\r\ncleanupret:                                       ; preds = %cleanuppad, %finally2\r\n  call void @_d_leave_cleanup(i8* null) [ \"funclet\"(token %3) ]\r\n  cleanupret from %3 unwind to caller\r\n\r\npostinvoke:                                       ; preds = %0\r\n  %5 = bitcast %nothrow.S* %b to i8*              ; [#uses = 1]\r\n  call void @llvm.memset.p0i8.i64(i8* %5, i8 0, i64 1, i32 1, i1 false)\r\n  invoke void @_D7nothrow8Throwing3barMFZv(%nothrow.Throwing* nonnull %t) #4\r\n          to label %postinvoke10 unwind label %cleanuppad7\r\n\r\ncleanuppad3:                                      ; preds = %cleanupret8, %0\r\n  %6 = cleanuppad within none []                  ; [#uses = 4]\r\n  %7 = call i1 @_d_enter_cleanup(i8* null) [ \"funclet\"(token %6) ] ; [#uses = 1]\r\n  br i1 %7, label %finally15, label %cleanupret4\r\n\r\nfinally15:                                        ; preds = %cleanuppad3\r\n  call void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %a) #0 [ \"funclet\"(token %6) ]\r\n  br label %cleanupret4\r\n\r\ncleanupret4:                                      ; preds = %cleanuppad3, %finally15\r\n  call void @_d_leave_cleanup(i8* null) [ \"funclet\"(token %6) ]\r\n  cleanupret from %6 unwind label %cleanuppad\r\n\r\nfinally6:                                         ; preds = %toElem.success\r\n  call void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %b) #0\r\n  br label %try.success\r\n\r\npostinvoke10:                                     ; preds = %postinvoke\r\n  call void @_D7nothrow1S3fooMFNbZv(%nothrow.S* nonnull %b) #0\r\n  %8 = bitcast %nothrow.S* %__slS54 to i8*        ; [#uses = 1]\r\n  %.padding = getelementptr inbounds i8, i8* %8, i32 0 ; [#uses = 1, type = i8*]\r\n  call void @llvm.memset.p0i8.i64(i8* %.padding, i8 0, i64 1, i32 1, i1 false)\r\n  call void @_D7nothrow1S3fooMFNbZv(%nothrow.S* nonnull %__slS54) #0\r\n  br label %dtor.__slS54\r\n\r\ncleanuppad7:                                      ; preds = %postinvoke\r\n  %9 = cleanuppad within none []                  ; [#uses = 4]\r\n  %10 = call i1 @_d_enter_cleanup(i8* null) [ \"funclet\"(token %9) ] ; [#uses = 1]\r\n  br i1 %10, label %finally69, label %cleanupret8\r\n\r\nfinally69:                                        ; preds = %cleanuppad7\r\n  call void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %b) #0 [ \"funclet\"(token %9) ]\r\n  br label %cleanupret8\r\n\r\ncleanupret8:                                      ; preds = %cleanuppad7, %finally69\r\n  call void @_d_leave_cleanup(i8* null) [ \"funclet\"(token %9) ]\r\n  cleanupret from %9 unwind label %cleanuppad3\r\n\r\ndtor.__slS54:                                     ; preds = %postinvoke10\r\n  call void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %__slS54) #0\r\n  br label %toElem.success\r\n\r\ntoElem.success:                                   ; preds = %dtor.__slS54\r\n  br label %finally6\r\n\r\ntry.success:                                      ; preds = %finally6\r\n  br label %finally1\r\n\r\ntry.success11:                                    ; preds = %finally1\r\n  br label %finally\r\n\r\ntry.success12:                                    ; preds = %finally\r\n  ret i32 0\r\n}\r\n```\r\n\r\nDebug:\r\n```LL\r\ndefine i32 @_Dmain({ i64, { i64, i8* }* } %unnamed) #0 comdat personality i32 (i8*, i8*, i8*, i8*)* @__CxxFrameHandler3 {\r\n  %t = alloca %nothrow.Throwing, align 1          ; [#uses = 5, size/byte = 1]\r\n  %a = alloca %nothrow.S, align 1                 ; [#uses = 4, size/byte = 1]\r\n  %b = alloca %nothrow.S, align 1                 ; [#uses = 4, size/byte = 1]\r\n  %__slS54 = alloca %nothrow.S, align 1           ; [#uses = 4, size/byte = 1]\r\n  %1 = bitcast %nothrow.Throwing* %t to i8*       ; [#uses = 1]\r\n  call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 1, i32 1, i1 false)\r\n  %2 = bitcast %nothrow.S* %a to i8*              ; [#uses = 1]\r\n  call void @llvm.memset.p0i8.i64(i8* %2, i8 0, i64 1, i32 1, i1 false)\r\n  invoke void @_D7nothrow1S3fooMFNbZv(%nothrow.S* nonnull %a) #0\r\n          to label %postinvoke7 unwind label %cleanuppad3\r\n\r\nfinally:                                          ; preds = %try.success23\r\n  call void @_D7nothrow8Throwing6__dtorMFZv(%nothrow.Throwing* nonnull %t) #0\r\n  br label %try.success24\r\n\r\nfinally1:                                         ; preds = %try.success\r\n  invoke void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %a) #0\r\n          to label %postinvoke unwind label %cleanuppad\r\n\r\npostinvoke:                                       ; preds = %finally1\r\n  br label %try.success23\r\n\r\ncleanuppad:                                       ; preds = %finally15, %cleanupret4, %finally1\r\n  %3 = cleanuppad within none []                  ; [#uses = 4]\r\n  %4 = call i1 @_d_enter_cleanup(i8* null) [ \"funclet\"(token %3) ] ; [#uses = 1]\r\n  br i1 %4, label %finally2, label %cleanupret\r\n\r\nfinally2:                                         ; preds = %cleanuppad\r\n  call void @_D7nothrow8Throwing6__dtorMFZv(%nothrow.Throwing* nonnull %t) #0 [ \"funclet\"(token %3) ]\r\n  br label %cleanupret\r\n\r\ncleanupret:                                       ; preds = %cleanuppad, %finally2\r\n  call void @_d_leave_cleanup(i8* null) [ \"funclet\"(token %3) ]\r\n  cleanupret from %3 unwind to caller\r\n\r\npostinvoke7:                                      ; preds = %0\r\n  invoke void @_D7nothrow8Throwing3barMFZv(%nothrow.Throwing* nonnull %t) #0\r\n          to label %postinvoke8 unwind label %cleanuppad3\r\n\r\npostinvoke8:                                      ; preds = %postinvoke7\r\n  %5 = bitcast %nothrow.S* %b to i8*              ; [#uses = 1]\r\n  call void @llvm.memset.p0i8.i64(i8* %5, i8 0, i64 1, i32 1, i1 false)\r\n  invoke void @_D7nothrow8Throwing3barMFZv(%nothrow.Throwing* nonnull %t) #0\r\n          to label %postinvoke15 unwind label %cleanuppad11\r\n\r\npostinvoke10:                                     ; preds = %finally9\r\n  br label %try.success\r\n\r\ncleanuppad3:                                      ; preds = %finally913, %cleanupret12, %finally9, %postinvoke7, %0\r\n  %6 = cleanuppad within none []                  ; [#uses = 4]\r\n  %7 = call i1 @_d_enter_cleanup(i8* null) [ \"funclet\"(token %6) ] ; [#uses = 1]\r\n  br i1 %7, label %finally15, label %cleanupret4\r\n\r\nfinally15:                                        ; preds = %cleanuppad3\r\n  invoke void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %a) #0 [ \"funclet\"(token %6) ]\r\n          to label %postinvoke6 unwind label %cleanuppad\r\n\r\npostinvoke6:                                      ; preds = %finally15\r\n  br label %cleanupret4\r\n\r\ncleanupret4:                                      ; preds = %cleanuppad3, %postinvoke6\r\n  call void @_d_leave_cleanup(i8* null) [ \"funclet\"(token %6) ]\r\n  cleanupret from %6 unwind label %cleanuppad\r\n\r\nfinally9:                                         ; preds = %toElem.success\r\n  invoke void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %b) #0\r\n          to label %postinvoke10 unwind label %cleanuppad3\r\n\r\npostinvoke15:                                     ; preds = %postinvoke8\r\n  invoke void @_D7nothrow1S3fooMFNbZv(%nothrow.S* nonnull %b) #0\r\n          to label %postinvoke16 unwind label %cleanuppad11\r\n\r\npostinvoke16:                                     ; preds = %postinvoke15\r\n  %8 = bitcast %nothrow.S* %__slS54 to i8*        ; [#uses = 1]\r\n  %.padding = getelementptr inbounds i8, i8* %8, i32 0 ; [#uses = 1, type = i8*]\r\n  call void @llvm.memset.p0i8.i64(i8* %.padding, i8 0, i64 1, i32 1, i1 false)\r\n  invoke void @_D7nothrow1S3fooMFNbZv(%nothrow.S* nonnull %__slS54) #0\r\n          to label %postinvoke22 unwind label %cleanuppad18\r\n\r\npostinvoke17:                                     ; preds = %dtor.__slS54\r\n  br label %toElem.success\r\n\r\ncleanuppad11:                                     ; preds = %dtor.__slS5420, %cleanupret19, %dtor.__slS54, %postinvoke15, %postinvoke8\r\n  %9 = cleanuppad within none []                  ; [#uses = 4]\r\n  %10 = call i1 @_d_enter_cleanup(i8* null) [ \"funclet\"(token %9) ] ; [#uses = 1]\r\n  br i1 %10, label %finally913, label %cleanupret12\r\n\r\nfinally913:                                       ; preds = %cleanuppad11\r\n  invoke void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %b) #0 [ \"funclet\"(token %9) ]\r\n          to label %postinvoke1014 unwind label %cleanuppad3\r\n\r\npostinvoke1014:                                   ; preds = %finally913\r\n  br label %cleanupret12\r\n\r\ncleanupret12:                                     ; preds = %cleanuppad11, %postinvoke1014\r\n  call void @_d_leave_cleanup(i8* null) [ \"funclet\"(token %9) ]\r\n  cleanupret from %9 unwind label %cleanuppad3\r\n\r\ndtor.__slS54:                                     ; preds = %postinvoke22\r\n  invoke void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %__slS54) #0\r\n          to label %postinvoke17 unwind label %cleanuppad11\r\n\r\npostinvoke22:                                     ; preds = %postinvoke16\r\n  br label %dtor.__slS54\r\n\r\ncleanuppad18:                                     ; preds = %postinvoke16\r\n  %11 = cleanuppad within none []                 ; [#uses = 4]\r\n  %12 = call i1 @_d_enter_cleanup(i8* null) [ \"funclet\"(token %11) ] ; [#uses = 1]\r\n  br i1 %12, label %dtor.__slS5420, label %cleanupret19\r\n\r\ndtor.__slS5420:                                   ; preds = %cleanuppad18\r\n  invoke void @_D7nothrow1S6__dtorMFNbZv(%nothrow.S* nonnull %__slS54) #0 [ \"funclet\"(token %11) ]\r\n          to label %postinvoke1721 unwind label %cleanuppad11\r\n\r\npostinvoke1721:                                   ; preds = %dtor.__slS5420\r\n  br label %cleanupret19\r\n\r\ncleanupret19:                                     ; preds = %cleanuppad18, %postinvoke1721\r\n  call void @_d_leave_cleanup(i8* null) [ \"funclet\"(token %11) ]\r\n  cleanupret from %11 unwind label %cleanuppad11\r\n\r\ntoElem.success:                                   ; preds = %postinvoke17\r\n  br label %finally9\r\n\r\ntry.success:                                      ; preds = %postinvoke10\r\n  br label %finally1\r\n\r\ntry.success23:                                    ; preds = %postinvoke\r\n  br label %finally\r\n\r\ntry.success24:                                    ; preds = %finally\r\n  ret i32 0\r\n}\r\n```"}}
{"actor":{"display_login":"kinke"}}