Document Number: N2236
Submitter: Martin Sebor
Submission Date: April 5, 2018
Subject: Using Attribute deprecated

Summary

Document N2214 - The deprecated attribute proposes to extend C to support a new attribute for developers of programming interfaces to annotate APIs as deprecated and have compilers issue diagnostics when they are used. The attribute was first introduced in C++ 2011 and has been implemented in several C++ compilers for a number of years. The C++ attribute was modeled in part on the GCC feature __attribute__ ((deprecated)), and in part on the Microsoft Visual C/C++ feature __declspec (deprecated). Both of these have been available in a number of C and C++ compilers alike for well over a decade.

The proposed specification of the semantics of the attribute is quoted below for reference.

Semantics

-1- [Note: Implementations may use the deprecated attribute to produce a diagnostic message in case the program refers to name or entity other than to declare it, after a declaration that specifies the attribute. The diagnostic message may include text provided within the deprecated-argument of any deprecated attribute applied to the name or entity. — end note]

-2- A name or entity declared without the deprecated attribute can later be redeclared with the attribute and vice versa. An entity is considered marked after the first declaration that marks it.

-3- EXAMPLE

	  [[deprecated]] void f(void);
	  void g(void) {
	      f();
	  }
Implementations are encouraged to warn that f is deprecated at the function call expression within g.

Beyond the informative example, the proposed semantics leave it entirely at the discretion of implementations when a compiler might issue a diagnostic for a deprecated API. As it turns out, existing implementations have come up with different and in some cases incompatible rules for when to trigger such a warning. As a result, as APIs mature and as their authors (including C++ standard library implementers) increasingly look to make use of the standard attributes in portable code, this under-specification is turning out to be a serious impediment to usability. It makes it effectively impossible to use the attribute to deprecate a non-trivial API in a way that produces the expected results with the implementations that support the attribute. By non-trivial we mean an API that consists of one or more types and one or more functions that use the types, some or all of which need to be deprecated without triggering deprecation warnings for the declarations of the API itself.

The example program below illustrates the problem. We present it to start a discussion and to provide motivation for flushing out the specification of the details to a sufficient extent to eliminate the usability problems before the attribute is adopted in C2X.

The comments in the example indicate the implementation that issues either a deprecation warning for the declared entity, or a warning indicating it doesn't support the attribute in that context. All compilers were the most recent release at the time. Besides the compilers mentioned in the comments the test program was also compiled using Clang. It produced no warnings. We include both the historical and widely supported attribute __attribute__((deprecated)) and the C++ standard attribute [[deprecated]] for comparison.

Note the results with the historical attribute are sometimes different even for the same implementation depending on the attribute's placement within the same declaration.

For additional background refer to the committee email discussion at (SC22WG14.14953) deprecating APIs using the deprecated attribute.

      #if __cplusplus
      #  define D [[deprecated]]                 // C++ only
      #else
      #  define D __attribute__ ((deprecated))   // C only
      #endif

      D typedef int I;
      D void fi (I);          // G++

      D extern I gi;          // G++, MSVC
      D extern I ga[];        // G++, MSVC

      enum D E { e0 = 2 };
      D extern I gae[e0];     // G++, MSVC

      D void fe (enum E);     // GCC, G++
      struct D S {
          I mi;               // GCC, G++, MSVC
          I ma[e0];           // GCC, G++, MSVC
          enum E me;          // GCC, G++
          struct S *mps;
      };

      D void fs (struct S);   // GCC, G++

      D extern enum E ge;     // G++
      D extern struct S gs;   // G++

      enum { ex0 D = 2 };     // ICC (attribute ignored)

      struct T {
          D I mi;             // GCC, G++, ICC, ICC+, MSVC
          D I ma[e0];         // GCC, G++, ICC, ICC+, MSVC
          D int mb[ex0];      // GCC, G++
          D enum E me;        // GCC, G++, ICC+, ICC
          D struct S *mps;    // GCC, G++, ICC, ICC+
      };