3

I've gotten a piece of code which applies __attribute__((const)) to some functions. Now, I'd rather not remove it when it's usable, but on the other hand, I do want to be more portable, so - I want to say

#if some condition here
#define ATTRIBUTE(an_attribute)  __attribute__((an_attribute))
#else
#define ATTRIBUTE(an_attribute)  
#endif

void foo(int x) ATTRIBUTE(const)

What should the condition be?

Notes:

  • I know that, with C++17, we have this as a proper C++ attribute; but I can't assume C++17 is used. In fact, let's assume it isn't to make things simple.
  • Extra points if you can also answer the question for __attribute__((pure)).
einpoklum
  • 118,144
  • 57
  • 340
  • 684

2 Answers2

3

GCC provides these attributes under the standard attribute syntax introduced in C++11:

[[gnu::const]] // or [[gnu::pure]]
void foo(int x);

As of C++17, compilers are required to ignore unknown attributes without it causing an error. In practice, compilers will often warn for unknown attributes (with an option to turn that warning off, of course). From what I've seen on Compiler Explorer and from what I remember, compilers older than C++17 also typically warn as well, once they understand the syntax at all. The main compiler I would further test is MSVC, but Compiler Explorer doesn't go too far back in MSVC versions.

If you already have the macro and don't want to change all its uses, you could work this in:

#define ATTRIBUTE(an_attribute) [[gnu::an_attribute]]

If this is not a reasonable solution, I suspect you would have to check against specific compilers and versions in the condition, unfortunately.

chris
  • 60,560
  • 13
  • 143
  • 205
  • Oh, and - will other compilers will just ignore this, even before C++17? – einpoklum Oct 20 '19 at 19:08
  • @einpoklum, I updated the answer after testing available older versions of MSVC, GCC, Clang, and ICC on Compiler Explorer. They warned back then as well, which is consistent with my memory. – chris Oct 20 '19 at 19:15
  • One thing that is worth watching out for is when GCC, Clang, and ICC actually started to provide these attributes under the standard syntax. That, I don't have a good answer on. It might well be that this answer won't work for you, but in that case, I hope that it at least helps someone down the line with a similar problem. – chris Oct 20 '19 at 19:18
  • This is pretty good. I don't suppose it'll work for the __printf__ attribute, would it? – einpoklum Oct 20 '19 at 19:23
  • @einpoklum, [Sure does!](https://gcc.godbolt.org/z/6W-OlU) I'm inclined to say all the `__attribute__` attributes are available, but I'd need to go find something more concrete. – chris Oct 20 '19 at 19:33
1

__attribute__ is a GNU extension. Only GNU compilers and compilers that claim to be GNU (such as Clang and ICC) support it. So you can do this:

#ifdef __GNUC__
# define ATTRIBUTE(x) __attribute__ (x)
# else
# define ATTRIBUTE(x)
#endif

const was introduced in GCC 2.5, and pure during GCC 2.96 development, so it does not make sense to test separate for their support: these compiler versions will not be able to compile current C++ code anyway. (__attribute__ itself was introduced with GCC 2.0. I think the C++ front end has always supported it.)

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • +1, and if you could also mention @chris' answer about C++11 attributres (preferably with a link), I could make this the accepted answer. – einpoklum Oct 21 '19 at 08:48