April 26, 2018·4 min read·engineeringcstandardsdiagnosticsattributes

Deprecation warnings on the Brno C agenda

WG14's Brno agenda includes proposed attributes and a paper showing inconsistent deprecation diagnostics. The difficult question is how an API can deprecate its types without warning about its own declarations.

A library can deprecate a type and then trigger warnings while declaring the functions that use it. That makes deprecation more complicated than attaching a warning to a function call. Martin Sebor's N2236 paper, submitted on April 5, documents differences among compilers and asks WG14 to specify the behavior more precisely before adding the attribute to C.

The subject appears on the Brno meeting agenda. WG14's meeting schedule places the meeting on April 23 through 26 at Red Hat in Brno. The agenda and submitted paper establish what was under discussion. They do not establish a final resolution, so the useful account at this point is the design problem the committee was asked to consider.

C's small language and its importance at interface boundaries make this issue interesting to me. A deprecation annotation communicates a maintenance decision through the compiler. That communication becomes less useful when including the library's own declarations produces warnings that an application author cannot remove without changing the interface itself.

Declaring an old interface can look like using it

Sebor describes a nontrivial API as having types and functions that use those types. An author may want to deprecate some or all of those declarations. The diagnostic policy must then distinguish the library's declaration of that API from application code that depends on it.

The proposed semantics quoted in N2236 let implementations diagnose a reference to a deprecated name or entity, except a reference made to declare it. They permit a diagnostic message to include text from the attribute argument. A declaration can also acquire the attribute on a later redeclaration. The first declaration that marks the entity establishes its deprecated status.

That description leaves room for disagreement once one deprecated declaration refers to another. A function declaration may mention a deprecated typedef as its parameter type. A structure may contain a member of a deprecated type. Whether those references deserve a warning is a policy question with immediate consequences for headers.

The paper gives a compact example using the existing GNU attribute spelling:

#define D __attribute__((deprecated))

D typedef int I;
D void fi(I);

This is an extension-based C example, not a claim that the proposed standard attribute is already part of C. It follows two declarations in Sebor's test program. The function is itself marked deprecated, but its parameter mentions a typedef that has already acquired the same marking. A compiler has to decide whether that reference should produce an additional diagnostic.

Existing practice disagrees about the boundary

N2236 compares the historical GNU spelling with the C++ standard spelling. Its examples include external objects, enumeration types and structure members. Comments record which tested compilers issued a deprecation warning or reported that an attribute was unsupported in that position. Sebor also reports that Clang produced no warnings for his test program.

The scope of that evidence matters. These are results for the program and compiler versions examined by the paper. They demonstrate inconsistent practice, but they do not establish a universal rule for every use of those compilers. Sebor further notes that moving the historical attribute within a declaration can change the result even with the same implementation.

This makes syntax compatibility insufficient as a migration goal. Two implementations can accept the same attribute and still disagree about which references count as warning-worthy use. An API author then cannot determine the resulting diagnostic behavior merely by checking whether the compiler recognizes the spelling.

The distinction also affects the usefulness of the message for an application developer. A warning attached to an application's function call identifies a dependency the developer can replace. A warning attached to a library declaration may identify an intentional relationship inside an API that the application only includes. Both diagnostics concern a deprecated entity, but they ask different people to take action.

Attributes share the agenda with the object model

Brno's agenda schedules proposed deprecated, nodiscard, fallthrough and maybe_unused attributes for Tuesday morning. It separately schedules N2236 for Thursday afternoon. That separation gives the implementation evidence its own place alongside the proposal for the annotation itself.

The same agenda includes pointer provenance and unspecified-value papers, as well as thread-local state for library functions. These subjects concern different mechanisms, but each asks the standard to define behavior that source-level familiarity alone does not settle. A familiar declaration or operation can still leave a significant implementation choice unresolved.

I favor a deprecation facility whose diagnostic boundary is clear enough for library authors to use deliberately. That does not require treating every compiler warning as a language error. It requires enough agreement about the cases to let authors express an API's status without making its own declarations a persistent source of noise.

N2236 stops at a request for discussion and more complete specification. The paper's concrete contribution is the collection of declarations on which implementations disagree. Resolving those cases would give a proposed C attribute a more useful contract than acceptance of its syntax alone.