Skip to content

Variadic CHKERRQ()

Jacob Faibussowitsch requested to merge jacobf/2022-02-23/variadic-chkerr into main

What this MR does:

  • Make CHKERRQ() and derivatives wrap all function calls chkerrconvert.py

    - ierr = Foo(...);CHKERRQ(ierr);
    + CHKERRQ(Foo(...));
  • Remove dangling PetscErrorCode declarations processpaths.py

  • Wrap both PetscInitialize() and PetscFinalize():

    - ierr = PetscInitialize(...);if (ierr) return ierr;
    + CHKERRQ(PetscInitialize());
    - ierr = PetscFinalize();
    - return ierr;
    + CHKERRQ(PetscFinalize());
    + return 0;
  • Rename the following findreplace.py:

    • CHKERRQ() -> PetscCall()
    • CHKERRV() -> PetscCallVoid()
    • CHKERRMPI() -> PetscCallMPI()
    • CHKERRABORT() -> PetscCallAbort()
    • CHKERRCONTINUE() -> PetscCallContinue()
    • CHKERRXX() -> PetscCallThrow()
    • CHKERRCXX() -> PetscCallCXX()
    • CHKERRCUDA() -> PetscCallCUDA()
    • CHKERRCUBLAS() -> PetscCallCUBLAS()
    • CHKERRCUSPARSE() -> PetscCallCUSPARSE()
    • CHKERRCUSOLVER() -> PetscCallCUSOLVER()
    • CHKERRCUFFT() -> PetscCallCUFFT()
    • CHKERRCURAND() -> PetscCallCURAND()
    • CHKERRHIP() -> PetscCallHIP()
    • CHKERRHIPBLAS() -> PetscCallHIPBLAS()
    • CHKERRHIPSOLVER() -> PetscCallHIPSOLVER()
    • CHKERRQ_CEED() -> PetscCallCEED()
    • CHKERR_FORTRAN_VOID_FUNCTION() -> PetscCallFortranVoidFunction()
  • PETSc error handling now "works" whether or not PetscInitialize() has been called (PetscError() now checks PetscErrorHandlingInitialized)

  • Roughly 1500 PetscCheckFalse() -> PetscCheck() conversions

  • Fix the clang linters' PetscValidXXXPointer() recommendation system (cc @joseroman). Previously it would only check the arguments index into the parent-functions argument was correct. It now also recommends more specific PetscValidXXXPointer() if applicable:

ERROR 18: /Users/jacobfaibussowitsch/soft/petsc/src/sys/tests/linter/testValidPointers.c:31:21
'b' of derived type 'char *', canonical type 'char'
  29: /* incorrect */
  30: PetscValidCharPointer(a,2);
> 31: PetscValidPointer(b,3);
                        ^
  32: PetscValidPointer(c,4);
  33: PetscValidPointer(d,5);

Incorrect use of PetscValidPointer(), use PetscValidCharPointer() instead

Misc:

Elisp helper to wrap a line or region with CHKERRQ()

(defun jf--insert-chkerr-func (begin end &optional chkerr_func)
  "Wrap a region in CHKERR_FUNC()"
  ;; make sure we are at the start of region
  (goto-char begin)
  (unless chkerr_func
    ;; if chkerr_func isn't set, try and determine which one we want
    (setq chkerr_func
          (pcase (buffer-substring-no-properties begin end)
            ((rx bos "MPI"       ) "PetscCallMPI"       )
            ((rx bos "cuda"      ) "PetscCallCUDA"      )
            ((rx bos "cublas"    ) "PetscCallCUBLAS"    )
            ((rx bos "cusolver"  ) "PetscCallCUSOLVER"  )
            ((rx bos "hipblas"   ) "PetscCallHIPBLAS"   )
            ((rx bos "hipsolver" ) "PetscCallHIPSOLVER" )
            ((rx bos "hip"       ) "PetscCallHIP"       )
            ((rx bos "cupmblas"  ) "PetscCallCUPMBLAS"  )
            ((rx bos "cupmsolver") "PetscCallCUPMSOLVER")
            ((rx bos "cupm"      ) "PetscCallCUPM"      )
            ;; default
            (_                     "PetscCall"          ))))

  (unless (string-equal (thing-at-point 'symbol) chkerr_func)
    (insert-before-markers chkerr_func ?\()
    (goto-char (+ end 1 (length chkerr_func)))
    (insert-char ?\))
    (unless (char-equal (following-char) ?\;)
      (insert-char ?\;))))

(defun jf/insert-chkerr-func (&optional chkerr_func)
  "Intelligently wrap current line in CHKERR_FUNC()"
  (interactive)
  (save-excursion
    (let ((using-region (use-region-p)))
      (unless using-region
        ;; go to start of indented line
        (back-to-indentation)
        (let ((eol (line-end-position)))
          ;; skip any chars that:
          ;; ^ - NOT
          ;; w - word constituent (including numbers)
          ;; _ - symbol constituent
          (skip-syntax-forward "^w_" eol)
          ;; special handling of keywords
          (while (looking-at-p "\\(for\\|while\\|switch\\|do\\|if\\|else\\|case\\)\s+")
            ;; special handling here, forward-list would skip to EOL for these
            (if (looking-at-p "\\(do\\|else\\|case\\)\s+")
                (forward-word)
              (forward-list))
            (skip-syntax-forward "^w_" eol)))
        ;; set start of region
        (push-mark nil t t)
        ;; skip to end of symbol
        (forward-list))
      (with-demoted-errors "ERROR wrapping line in CHKERR_FUNC: %s"
        (jf--insert-chkerr-func (region-beginning) (region-end) chkerr_func))
      (unless using-region (pop-mark)))
    (indent-according-to-mode)))

;; bind it
(global-set-key (kbd "C-c c") 'jf/insert-chkerr-func)
;; for those living in the 21st century
(bind-key "C-c c" 'jf/insert-chkerr-func)

With the point anywhere on a given line it will "do the right" thing for

Foo(asdasdasdasd)
// becomes
PetscCall(Foo(asdasdasdasd));

Foo(asdasdasdasd); // note semi-colon
// becomes
PetscCall(Foo(asdasdasdasd));

PetscCall(Foo(asdasdasdasd));
// becomes
PetscCall(Foo(asdasdasdasd)); // note no change

if (asdasdasd) { for (asdasdasd;ada;sda) { while (xasdads) { Foo(asdasdad); } }}
// becomes
if (asdasdasd) { for (asdasdasd;ada;sda) { while (xasdads) { PetscCall(Foo(asdasdad)); } } }

} else {Foo(asdasdasd);}
// becomes
} else {PetscCall(Foo(asdasdasd));}

// if some insertion fails, then it will do the insertion on a region (shown with "[]") too
F[ooBarBaz(asdas]dasd)
// becomes
FPetscCall(ooBarBaz(asdas);dasd)

// it auto-detect which PetscCall() to insert:
MPI_Comm_size(..);
// becomes
PetscCallMPI(MPI_Comm_size(...));

// and so on...
Edited by Jacob Faibussowitsch

Merge request reports