Skip to content

Add OIIO_NODISCARD to ImageInput create/open/read methods#5111

Open
mvanhorn wants to merge 1 commit intoAcademySoftwareFoundation:mainfrom
mvanhorn:osc/4781-nodiscard-imageinput
Open

Add OIIO_NODISCARD to ImageInput create/open/read methods#5111
mvanhorn wants to merge 1 commit intoAcademySoftwareFoundation:mainfrom
mvanhorn:osc/4781-nodiscard-imageinput

Conversation

@mvanhorn
Copy link
Copy Markdown

Summary

Adds OIIO_NODISCARD to ImageInput::create(), open(), read_image(), and read_scanlines() methods. Callers ignoring return values from these methods now get a compiler warning.

Why this matters

As noted in #4781, it's easy to accidentally ignore the bool return from read_image() or open(). These methods return false on failure, and silently proceeding with bad data leads to hard-to-debug issues. create() returns a unique_ptr that should never be discarded.

Changes

  • src/include/OpenImageIO/imageio.h: Added OIIO_NODISCARD to 14 method declarations in the ImageInput class, covering create() (2 overloads), open() (4 overloads), read_image() (4 overloads), and read_scanlines() (4 overloads).

Scoped to ImageInput only per @lgritz's guidance to start with one class and iterate.

Testing

  • Header compiles (syntax validated)
  • No behavioral changes - annotation only

Partial fix for #4781

This contribution was developed with AI assistance (Claude Code).

@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla bot commented Mar 25, 2026

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: mvanhorn / name: Matt Van Horn (50ed282)

Annotates ImageInput::create(), open(), read_image(), and
read_scanlines() methods with OIIO_NODISCARD so callers get a
compiler warning when they ignore return values that indicate
success or failure.

Partial fix for AcademySoftwareFoundation#4781 - scoped to ImageInput class per maintainer
guidance to "pick just one or two classes" and iterate.

Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
@mvanhorn mvanhorn force-pushed the osc/4781-nodiscard-imageinput branch from 6ac7875 to 50ed282 Compare March 25, 2026 17:07
@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented Mar 25, 2026

Did you not run the CI before submitting the PR? Many of the CI job variants are failing -- for the obvious reason that OIIO itself calls these functions, often without checking the return code (I know, bad), so those will now be errors and break our build. Changes to the function declarations to add these annotations must be accompanied by changes to the call sites where we have up until now neglected the return values.

That's part of why I wanted to go slowly, a few calls at a time, because we'll want to carefully review and ensure that all the places that we must add the error checks are handling those previously-unchecked errors sensibly, so we want small, easily reviewable PRs for that sweeping set of changes.

As for why some job variants pass and others fail, I suspect that is reflecting which compiler, version, and C++ standard they are using.

@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented Mar 25, 2026

I like the idea of migrating to heavy use of nodiscard, but I fear how much user code will have broken builds as a result (as our own was, revealed by the CI!). Maybe there's a way to gently transition people?

I think there are two classes of return values we may wish to annotate as "nodiscard":

  1. Cases where the whole point is to use the return value, and ignoring it would 100% mean a mistake on the user's part. An example would be ImageInput::create() -- if you don't capture the result, what the heck are you doing?

  2. Cases where the function performs some action and returns an error code, and while it's good practice to check every result for errors, failing to do so is a common mistake to make and may not be harmful in practice (though it could prevent you from catching legit errors that occur at runtime).

Definitely for case 1, we should not hesitate to annotate with OIIO_NODISCARD now.

But for case 2, I wonder what people think of the merits of creating a second macro OIIO_NODISCARD_ERROR, that is conditionally defined, maybe something like this (perhaps in platform.h):

    #ifndef OIIO_CHECK_DISCARDED_ERROR_RETURN
    #    define OIIO_CHECK_DISCARDED_ERROR_RETURN 0
    #endif
    #if OIIO_CHECK_DISCARDED_ERROR_RETURN
    #    define OIIO_NODISCARD_ERROR OIIO_NODISCARD
    #else
    #    define OIIO_NODISCARD_ERROR
    #endif

So what this would do is:

  • For now, by default, it allows user code to ignore error return codes.
  • Downstream/user code may build with -DOIIO_CHECK_DISCARDED_ERROR_RETURN=1 to force the full errors if they want. This will allow users to audit their code easily for this mistake, activating it at a time their convenience.
  • In a future release, we'll switch the default value from 0 to 1 so that it will catch all such errors unless a downstream project uses -DOIIO_CHECK_DISCARDED_ERROR_RETURN=0.
  • Eventually (a couple major releases later), maybe we will choose to remove the option entirely and always require errors to be checked.

So, for example, a method like ImageInput::read_scanline() would be annotated with OIIO_NODISCARD_ERROR rather than the less flexible OIIO_NODISCARD.

Opinions?

@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented Mar 25, 2026

As for why some job variants pass and others fail, I suspect that is reflecting which compiler, version, and C++ standard they are using.

It looks like clang is always flagging the nodiscard errors, but gcc never is. We should look into why this is the case -- I would have expected more recent gcc versions to also turn them into errors. Have we done something wrong, or perhaps is something else needed for clang?

@mvanhorn
Copy link
Copy Markdown
Author

You're right - I should have run CI before submitting. Apologies for the noise.

The two-tier approach makes sense. I'll rework this to:

  1. Hard [[nodiscard]] only on create() and open() - ignoring these is always a bug
  2. OIIO_NODISCARD_GENTLE (initially a no-op) for bool-returning methods like read_image() where ignoring is sloppy but not catastrophic
  3. Fix OIIO's own unchecked call sites so CI passes

On the clang vs gcc question: gcc only treats [[nodiscard]] violations as warnings (even with -Wall), while clang promotes them to errors when -Werror is active. OIIO's clang CI configs likely include -Werror, which explains why clang fails but gcc doesn't.

I'll push the reworked version with call site fixes shortly.

@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented Mar 25, 2026

I prefer OIIO_NODISCARD_ERROR rather than OIIO_NODISCARD_GENTLE, in case we later identify other cases (aside from error status returns) that we want to independently select as gentle or harsh.

@mvanhorn
Copy link
Copy Markdown
Author

Good call on OIIO_NODISCARD_ERROR - clearer that it's specific to error-status returns and leaves room for other nodiscard categories later. Will use that naming in the rework.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants