detecting deprecated functions in C++ - c++

In a C++ project documented with Doxygen, I have marked some functions as \deprecated in the Doxygen comments. Is there any way to use these comments (with Doxygen or another tool) in order to detect that another non-deprecated function is calling a deprecated one ? (The project is pretty big and going through all the classes would take a lot of time).
Thanks

If you are using GCC or clang to compile your code you could manually annotate functions.
__attribute__((__deprecated__))
void dep_fun() { }
Then calling dep_fun anywhere in your code will emit a diagnostic message.
If you placed doxygen's \deprecated annotation consistently you should be able to update the code automatically with tools like sed.

Building on Benjamins answer:
Some useful compiler directives:
#ifdef _MSC_VER
#define DEPRECATED __declspec(deprecated)
#elif defined(__GNUC__) | defined(__clang__)
#define DEPRECATED __attribute__((__deprecated__))
#else
#define DEPRECATED
#endif
//usage:
DEPRECATED void foo(int bar);
(warning: untested under clang and msc, only tested on GNUC.)

Related

Is it possible to determine or set compiler options from within the source code in gcc?

I have some code that requires a certain gcc compiler option (otherwise it won't compile). Of course, I can make sure in the makefile that for this particular source file the required option is set. However, it would much more helpful, if this option could be set for the respective compilation unit (or part of it) from within the source_file.cpp.
I know that warning messages can be switched on or off using #pragma GCC diagnostic, but what about the -fsomething type of options? I take it from this question that this is impossible.
But perhaps there is at least a way to check from within the code whether a certain -f option is on or not?
Note I'm not interested in finding the compiler flags from the binary, as was asked previously, nor from the command line.
In my experience, no. This is not the way you go about this. Instead, you put compiler/platform/OS specific code in your source, and wrap it with the appropriate ifdef statements. These include:
#ifdef __GNUC__
/*code for GNU C compiler */
#elif _MSC_VER
/*usually has the version number in _MSC_VER*/
/*code specific to MSVC compiler*/
#elif __BORLANDC__
/*code specific to borland compilers*/
#elif __MINGW32__
/*code specific to mingw compilers*/
#endif
Within this, you can have version-specific requirements and code:
#ifdef __GNUC__
# include <features.h>
# if __GNUC_PREREQ(4,0)
// If gcc_version >= 4.0
# elif __GNUC_PREREQ(3,2)
// If gcc_version >= 3.2
# else
// Else
# endif
#else
// If not gcc
#endif
From there, you have your makefile pass the appropriate compiler flags based on the compiler type, version, etc, and you're all set.
You can try using some #pragma. See GCC diagnostic pragmas & GCC function specific pragmas.
Otherwise, develop your GCC plugin or your MELT extension and have it provide a pragma which sets the appropriate variables or compiler state inside GCC (actually cc1plus)

Printing the c++ compiler name

I have been working with qt creator and recently tried to change the compiler from gcc to clang. Since I don't get any info (or can't see it) on whether this worked (I'm struggling to understand the interface) I wanted to ask if there's a way for my c++ code to print out the compiler under which it's being compiled.
Compilers set certain #defines to help out with things like this.
In your case,
#ifdef __GNUC__ //GCC
//do whatever GCC-specific stuff you need to do here
#endif
#ifdef __clang__ //clang
//do whatever clang-specific stuff you need to do here
#endif
This page on SourceForge shows a list of such compiler-specific #define values.
EDIT: as pointed out in the comments, clang sets __GNUC__, and possibly __GNUC_MINOR__ and __GNUC_PATCHLEVEL__. You might be better off using a double test to make sure clang isn't misleading you:
#if defined(__GNUC__) && !defined(__clang__)
//do whatever GCC-specific stuff you need to do here
#endif
Use the informational macros of boost.
#include <boost/config.hpp>
#ifdef BOOST_CLANG
printf("Successfully changed to clang\n");
#endif

cross platform macro for silencing unused variables warning

In porting a large piece of C++ code from Visual Studio (2008) to Xcode (4.4+), I encounter lines such as:
UNUSED_ALWAYS(someVar);
the UNUSED_ALWAYS(x) (through UNUSED(x)) macro expands to x which seems to silence Visual C++ just fine. It's not enough for Clang however.
With Clang, I usually use the #pragma unused x directive.
The UNUSED_ALWAYS and UNUSED macros are defined in an artificial windows.h header which I control that contains a number of utilities to help Xcode compile Windows stuff.
Is there a way to define UNUSED(x) to expand to #pragma unused x? I tried this, which Clang fails to accept:
#define UNUSED(x) #pragma unused(x)
I also tried:
#define UNUSED(x) (void)(x)
Which seems to work. Did I miss anything?
(void)x;
is fine; has always worked for me. You can't usually expand a macro to a #pragma, although there is usually a slightly different pragma syntax that can be generated from a macro (_Pragma on gcc and clang, __pragma on VisualC++).
Still, I don't actually need the (void)x anymore in C++, since you can simply not give a name to a function parameter to indicate that you don't use it:
int Example(int, int b, int)
{
... /* only uses b */
}
works perfectly fine.
Yup - you can use this approach for GCC and Clang:
#define MON_Internal_UnusedStringify(macro_arg_string_literal) #macro_arg_string_literal
#define MONUnusedParameter(macro_arg_parameter) _Pragma(MON_Internal_UnusedStringify(unused(macro_arg_parameter)))
although mine did have the (void) approach defined for clang, it appears that Clang now supports the stringify and _Pragma approach above. _Pragma is C99.
#define and #pragma both are preprocessor directives. You cannot define one macro to expand as preprocessor directive. Following would be incorrect:
#define MY_MACRO #if _WIN32
MY_MACRO cannot expand to #if _WIN32 for the compiler.
Your best bet is to define your own macro:
#define UNUSED(_var) _var

Portable UNUSED parameter macro used on function signature for C and C++

I'm interested in creating a macro for eliminating the unused variable warning.
This question describes a way to suppress the unused parameter warning by writing a macro inside the function code:
Universally compiler independent way of implementing an UNUSED macro in C/C++
But I'm interested in a macro that can be used in the function signature:
void callback(int UNUSED(some_useless_stuff)) {}
This is what I dug out using Google (source)
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*#unused#*/ x
#elif defined(__cplusplus)
# define UNUSED(x)
#else
# define UNUSED(x) x
#endif
Can this be further expanded for other compilers?
Edit: For those who can't understand how tagging works: I want a solution for both C and C++. That is why this question is tagged both C and C++ and that is why a C++ only solution is not acceptable.
The way I do it is like this:
#define UNUSED(x) (void)(x)
void foo(const int i) {
UNUSED(i);
}
I've not had a problem with that in Visual Studio, Intel, gcc and clang.
The other option is to just comment out the parameter:
void foo(const int /*i*/) {
// When we need to use `i` we can just uncomment it.
}
Just one small thing, better using __attribute__((__unused__)) as __attribute__((unused)), because unused could be somewhere defined as macro, personally I had a few issues with this situation.
But the trick I'm using is, which I found more readable is:
#define UNUSED(x) (void)x;
It works however only for the variables, and arguments of the methods, but not for the function itself.
After testing and following the comments, the original version mentioned in the question turned out to be good enough.
Using: #define UNUSED(x) __pragma(warning(suppress:4100)) x (mentioned in comments), might be necessary for compiling C on MSVC, but that's such a weird combination, that I didn't include it in the end.
Across many compilers I have used the following, excluding support for lint.
#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
# define PGM_GNUC_UNUSED __attribute__((__unused__))
#else
# define PGM_GNUC_UNUSED
#endif
Tested compilers: GCC, Clang, EKOPath, Intel C Compiler / Composer XE, MinGW32 on Cygwin / Linux / MSYS, MinGW-w64 on Cygwin / Linux, Sun ONE Studio / Oracle Solaris Studio, Visual Studio 2008 / 2010.
Example usage:
pgm_tsc_init (
PGM_GNUC_UNUSED pgm_error_t** error
)
{
...
}
PGM is the standard prefix for this C based project. GNUC is the convention from GLib for this attribute.
I think one compile warns about __attribute__ in certain circumstances but certainly no error.

How can I mark a C++ class method as deprecated?

I have a method in a C++ interface that I want to deprecate, with portable code.
When I Googled for this all I got was a Microsoft specific solution; #pragma deprecated and __declspec(deprecated).
If a general or fully-portable deprecation solution is not available, I will accept as a "second prize solution" one that can be used multiple specific compilers, like MSVC and a GCC.
In C++14, you can mark a function as deprecated using the [[deprecated]] attribute (see section 7.6.5 [dcl.attr.deprecated]).
The attribute-token deprecated can be used to mark names and entities whose use is still allowed, but is discouraged for some reason.
For example, the following function foo is deprecated:
[[deprecated]]
void foo(int);
It is possible to provide a message that describes why the name or entity was deprecated:
[[deprecated("Replaced by bar, which has an improved interface")]]
void foo(int);
The message must be a string literal.
For further details, see “Marking as deprecated in C++14”.
This should do the trick:
#ifdef __GNUC__
#define DEPRECATED(func) func __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED(func) func
#endif
...
//don't use me any more
DEPRECATED(void OldFunc(int a, float b));
//use me instead
void NewFunc(int a, double b);
However, you will encounter problems if a function return type has a commas in its name e.g. std::pair<int, int> as this will be interpreted by the preprocesor as passing 2 arguments to the DEPRECATED macro. In that case you would have to typedef the return type.
Edit: simpler (but possibly less widely compatible) version here.
Here's a simplified version of my 2008 answer:
#if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED
#endif
//...
//don't use me any more
DEPRECATED void OldFunc(int a, float b);
//use me instead
void NewFunc(int a, double b);
See also:
MSVC documentation for __declspec(deprecated)
GCC documentation for __attribute__((deprecated))
Clang documentation for __attribute__((deprecated))
In GCC you can declare your function with the attribute deprecated like this:
void myfunc() __attribute__ ((deprecated));
This will trigger a compile-time warning when that function is used in a .c file.
You can find more info under "Diagnostic pragmas" at
http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html
Here is a more complete answer for 2018.
These days, a lot of tools allow you to not just mark something as deprecated, but also provide a message. This allows you to tell people when something was deprecated, and maybe point them toward a replacement.
There is still a lot of variety in compiler support:
C++14 supports [[deprecated]]/[[deprecated(message)]].
__attribute__((deprecated)) is supported by GCC 4.0+ and ARM 4.1+
__attribute__((deprecated)) and __attribute__((deprecated(message))) is supported for:
GCC 4.5+
Several compilers which masquerade as GCC 4.5+ (by setting __GNUC__/__GNUC_MINOR__/__GNUC_PATCHLEVEL__)
Intel C/C++ Compiler going back to at least 16 (you can't trust __GNUC__/__GNUC_MINOR__, they just set it to whatever version of GCC is installed)
ARM 5.6+
MSVC supports __declspec(deprecated) since 13.10 (Visual Studio 2003)
MSVC supports __declspec(deprecated(message)) since 14.0 (Visual Studio 2005)
You can also use [[gnu::deprecated]] in recent versions of clang in C++11, based on __has_cpp_attribute(gnu::deprecated).
I have some macros in Hedley to handle all of this automatically which I keep up to date, but the current version (v2) looks like this:
#if defined(__cplusplus) && (__cplusplus >= 201402L)
# define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]]
# define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]]
#elif \
HEDLEY_GCC_HAS_EXTENSION(attribute_deprecated_with_message,4,5,0) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
HEDLEY_ARM_VERSION_CHECK(5,6,0)
# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
#elif \
HEDLEY_GCC_HAS_ATTRIBUTE(deprcated,4,0,0) || \
HEDLEY_ARM_VERSION_CHECK(4,1,0)
# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
#elif HEDLEY_MSVC_VERSION_CHECK(14,0,0)
# define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
# define HEDLEY_DEPRECATED(since) _declspec(deprecated)
# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
#else
# define HEDLEY_DEPRECATED(since)
# define HEDLEY_DEPRECATED_FOR(since, replacement)
#endif
I'll leave it as an exercise to figure out how to get rid of the *_VERSION_CHECK and *_HAS_ATTRIBUTE macros if you don't want to use Hedley (I wrote Hedley largely so I wouldn't have to think about that on a regular basis).
If you use GLib, you can use the G_DEPRECATED and G_DEPRECATED_FOR macros. They're not as robust as the ones from Hedley, but if you already use GLib there is nothing to add.
Dealing with portable projects it's almost inevitable that you at some point need a section of preprocessed alternatives for a range of platforms. #ifdef this #ifdef that and so on.
In such a section you could very well conditionally define a way to deprecate symbols. My preference is usually to define a "warning" macro since most toolchains support custom compiler warnings. Then you can go on with a specific warning macro for deprecation etc.
For the platforms supporting dedicated deprecation methods you can use that instead of warnings.
For Intel Compiler v19.0, use this as __INTEL_COMPILER evaluates to 1900:
# if defined(__INTEL_COMPILER)
# define DEPRECATED [[deprecated]]
# endif
Works for the following language levels:
C++17 Support (/Qstd=c++17)
C++14 Support (/Qstd=c++14)
C++11 Support (/Qstd=c++11)
C11 Support (/Qstd=c11)
C99 Support (/Qstd=c99)
The Intel Compiler has what appears a bug in that it does not support the [[deprecated]] attribute on certain language elements that all other compilers do. For an example, compile v6.0.0 of the (remarkly superb) {fmtlib/fmt} library on GitHub with Intel Compiler v19.0. It will break. Then see the fix in the GitHub commit.