What conditional compilation is needed around C++ attributes? - c++

I'm starting to add [[nodiscard]], [[noreturn]] and [[fallthrough]] to my code base, but I still worry the code might need to be used on an older C++ version.
I'm only worried about g++, clang, and Visual Studio.
To be safe should I make every single usage depend on a version check for the exact version it appeared? Or, do these compilers accept (or does the spec even mandate they accept) any [[attribute]] even if unknown, starting with C++11?
Were these allowed and ignored (or supported) even before C++11? (I ask not what the spec says but what the software actually did.)
#if __cplusplus >= 201703L
#define MyNamespace_NoReturnCPP17 [[noreturn]]
#else
#define MyNamespace_NoReturnCPP17
#endif
(Off subject but if I were on the C++ committee, I'd re-use the case keyword to do the same thing as switch, when followed by (, except it would in effect have an automatic break before each case label. And within the case's block (and nowhere else), fallthrough would be accepted as a keyword, that suppresses that automatic break.)
I note the C++14 spec 7.6.1.5 says behavior is "implemenation-defined" but I'm asking a more practical question about what compilers actually did. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
The C++17 spec 10.6.1.6 says "Any attribute-token that is not recognized by the implementation is ignored." That answers my question for C++17 and newer, but again my question is about earlier compilers. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf

To be safe should I make every single usage depend on a version check for the exact version it appeared? Or, do these compilers accept (or does the spec even mandate they accept) any [[attribute]] even if unknown, starting with C++11?
I prefer adding version checks for safety although mainstream compilers will throw a warning for unknown attributes.
gcc -Wno-ignored-attributes / -Wattributes
Clang -Wunknown-attributes
MSVC C5030
I'm not sure these warning options(and corresponding behavior) have been added since the first C++11 feature-complete version, so you'd better do some checks.
Were these allowed and ignored (or supported) even before C++11?
Since standard attributes syntax is supported starting from C++11, compilers will have trouble at the parsing stage. Demo

Related

(v) is actually (*&v) since when?

Could C++ standards gurus please enlighten me:
Since which C++ standard version has this statement failed because (v) seems to be equivalent to (*&v)?
I.e. for example the code:
#define DEC(V) ( ((V)>0)? ((V)-=1) : 0 )
...{...
register int v=1;
int r = DEC(v) ;
...}...
This now produces warnings under -std=c++17 like:
cannot take address of register variable
left hand side of operand must be lvalue
Many C macros enclose ALL macro parameters in parentheses, of which the above is meant only to be a representative example.
The actual macros that produce warnings are for instance
the RTA_* macros in /usr/include/linux/rtnetlink.h.
Short of not using/redefining these macros in C++, is there any workaround?
If you look at the revision summary of the latest C++1z draft, you'd see this in [diff.cpp14.dcl.dcl]
[dcl.stc]
Change: Removal of register storage-class-specifier.
Rationale: Enable repurposing of deprecated keyword in future
revisions of this International Standard.
Effect on original feature: A valid C++ 2014 declaration utilizing the register
storage-class-specifier is ill-formed in this International Standard.
The specifier can simply be removed to retain the original meaning.
The warning may be due to that.
register is no longer a storage class specifier, you should remove it. Compilers may not be issuing the right error or warnings but your code should not have register to begin with
The following is a quote from the standard informing people about what they should do with regards to register in their code (relevant part emphasized), you probably have an old version of that file
C.1.6 Clause 10: declarations [diff.dcl]
Change: In C++, register is not a storage class specifier.
Rationale: The storage class specifier had no effect in C++.
Effect on original feature: Deletion of semantically well-defined feature.
Difficulty of converting: Syntactic transformation.
How widely used: Common.
Your worry is unwarranted since the file in question does not actually contain the register keyword:
grep "register" /usr/include/linux/rtnetlink.h
outputs nothing. Either way, you shouldn't be receiving the warning since:
System headers don't emit warnings by default, at least in GCC
It isn't wise to try to compile a file that belongs to a systems project like the linux kernel in C++ mode, as there may be subtle and nasty breaking changes
Just include the file normally or link the C code to your C++ binary. Report a bug if you really are getting a warning that should normally be suppressed to your compiler vendor.

When to use Q_NULLPTR?

I see Q_NULLPTR being used liberally in Qt source code and examples, but I have found no documentation for what it is exactly and when it should be used.
For example in this official demonstration of the new Qt SerialBus module added in the new Qt v5.6:
if (!m_canDevice->connectDevice()) {
delete m_canDevice;
m_canDevice = Q_NULLPTR;
Did this serve the purpose of nullptr prior to that being added in C++11? If so, now that we have C++11, should I be using Q_NULLPTR?
PS: I tried searching the Qt source code for the definition of the macro but failed to find it.
Q_NULLPTR is a macro, that is replaced as nullptr if compiler supports c++11 and as NULL (which is replaced as 0) if it doesn't. If you use c++11, you can write nullptr instead; use NULL if you don't.
Did this serve the purpose of nullptr prior to that being added in
C++11? If so, now that we have C++11, should I be using Q_NULLPTR?
Yes (somewhat) and No respectively.
C++ was quite lacking back in the days, so Qt had its own stuff, which later became obsolete as C++ caught up on the features.
That being said, Q_NULLPTR is (was) not functionally the same as nullptr, (as Andrei noted, if C++11 is supported it expands to nullptr) it didn't give you the type safety, just syntax "sugar". It illustrated the intent to the person reading the code, not to the compiler as nullptr does.
Actually Q_NULLPTR had only one purpose: To allow use of nullptr without loosing support for compilers which didn't have C++11/C++0x support, as a direct use of nullptr would result in errors in such setups. The downside is that there are ambiguities of its fallback to NULL (or 0 in older Qt versions) which might result in unintended runtime behavior and limit the supported use cases compared to nullptr.
In the rare case that you target non C++11 compliant compilers, use Q_NULLPTR but make sure that the code works well when C++11 features are disabled. In all other situations nullptr is the better alternative as it results in compilation errors instead of buggy runtime behavior when used with legacy compilers. Qt 5.7 and later dropped the support for compilation without C++11 so there is no need for Q_NULLPTR if you depend on those versions.
There are other features like qMove or Q_DECL_OVERRIDE that give improved semantic when used on supporting compilers without breaking compilation on older compilers.
Use Q_NULLPTR to stay compiler independent.
If you now decide to use nullptr, your code won't compile with an older c++98 compiler. If you decide to use NULL, you lose the c++11 type safety, even if available in your current compiler.
For the same reason macros like qMove(x) and the corresponding define Q_COMPILER_RVALUE_REFS exists.

Does FENV_ACCESS pragma exist in C++11 and higher?

Reading a bug report for clang not supporting FENV_ACCESS pragma I've come across a comment:
Setting the rounding mode without using #pragma STDC FENV_ACCESS ON invokes undefined behavior. See C11 7.6.1/2. (This pragma does not exist in C++, so <cfenv> is unusable, but that's not our fault...)
Does this pragma really not exist in C++, rendering <cfenv> unusable? I've tried to search for it in the C++11 standard, but it really isn't mentioned at all. Are pragmas inherited from C along with function prototypes? Or are they actually not needed to avoid UB, since the C++ standard doesn't say anything about behavior being undefined when the pragma is not used (due to not mentioning the pragma at all)?
I searched the 2015 standard draft text and found no occurrences of FENV_ACCESS. http://cppreference.com also has nothing about it.
However, http://cplusplus.com does mention it (since it is not in the standard I think we must assume that this is advisory information at best):
http://www.cplusplus.com/reference/cfenv/FENV_ACCESS/
Quoting from cplusplus.com: (emphasis mine)
If set to on, the program informs the compiler that it might access the floating-point environment to test its status flags (exceptions) or run under control modes other than the one by default.
If set to off, the compiler may perform certain optimizations that can subvert these tests and mode changes, and thus accessing the floating-point environment in the cases described above, causes undefined behavior.
Whether the state of this pragma by default is on or off depends on the compiler settings and library implementation.
Given the unsettling lack of clarity, I would want to avoid its use if at all possible.
As ever, if the use was unavoidable I'd want to encapsulate it into one class that I can specialise and test for each architecture.
And then document the existence of this class and the trouble it may cause if the compiler, environment or library implementation is upgraded.
Update:
There is a very brief mention of the header in the c++ standard:
ยง 26.3 The floating-point environment [cfenv]
...
2 The header defines all functions, types, and macros the same as Clause 7.6 of the C standard.
Update:
Further information here: http://en.cppreference.com/w/cpp/preprocessor/impl
My reading of this is that the pragma is defined by the C11 standard, not the C++11 standard. Therefore use in a c++ program is strictly implementation/un-defined.

Why are trigraphs generating errors in modern C++ compilers?

Even in the GCC Compilers, the trigraphs are not getting compiled without explicitly specifying the trigraph attribute.
#include<stdio.h>
int main()
{
int a=4;
if((a==4) ??! (a==5))
printf("\nHello world!");
return 0;
}
This program saved as try.c gets compiled in GCC Compiler only when we specify gcc -Wall -trigraphs try.c and it still shows warnings.
Can you enlist some compilers that will treat and handle trigraphs without any errors or warnings?
Trigraphs were introduced by the 1989 ANSI C standard, and are retained in all later C standards (so far; the upcoming C23 standard will drop them). They also appear in the first ISO C++ standard, published in 1998, and in all later C++ standards up to and including C++14. (Trigraphs were removed in C++17. Thanks to Jonathan Leffler and dyp for tracking down the details.)
Quoting a draft of the C++17 standard:
Effect on original feature: Valid C ++ 2014 code that uses trigraphs
may not be valid or may have different semantics in this International
Standard. Implementations may choose to translate trigraphs as
specified in C ++ 2014 if they appear outside of a raw string literal,
as part of the implementation-defined mapping from physical source
file characters to the basic source character set.
They are not an optional feature in either language (prior to C++17); all conforming compilers must support them and interpret them as specified by the respective language standard.
For example, if this program:
#include <stdio.h>
int main(void) {
if ('|' == '??!') {
puts("ok");
}
else {
puts("oops");
}
return 0;
}
prints oops, then your compiler is non-conforming.
But many, perhaps most, C compilers are not fully conforming by default. As long as a compiler can be made to conform to the standard in some way, that's good enough as far as the standard is concerned. (gcc requires -pedantic and -std=... to do this.)
But even if a compiler is fully conforming, there's nothing in the standard that forbids a compiler from warning about anything it likes. A conforming C compiler must diagnose any violation of a syntax rule or constraint, but it can issue as many additional warnings as it likes -- and it needn't distinguish between required diagnostics and other warnings.
Trigraphs are very rarely used. The vast majority of development systems support directly all the characters for which trigraphs substitute: #, [, \, ], ^, {, |, }, ~.
In fact, it's likely that trigraphs are used accidentally more often than they're used correctly:
fprintf(stderr, "What just happened here??!\n");
Warning about trigraphs that might alter the meaning of a program (relative to the meaning it would have if the language didn't have trigraphs) is both permitted by the ISO standard and IMHO perfectly reasonable. Most compilers probably have options to turn off such warnings.
Conversely, for a C++17 compiler that doesn't implement trigraphs, it would be reasonable to warn about sequences that would have been treated as trigraphs in C++14 or earlier, and/or to provide an option to support trigraphs. Again, an option to disable such warnings would be a good thing.
GCC is allergic to trigraphs. You have to explicitly enable them:
gcc -trigraphs ...
The GCC 4.7.1 manual says:
-trigraphs
Support ISO C trigraphs. The -ansi option (and -std options for strict ISO
C conformance) implies -trigraphs.
It also says:
-Wtrigraphs
Warn if any trigraphs are encountered that might change the meaning of the
program (trigraphs within comments are not warned about). This warning is
enabled by -Wall.
They might be turned off by default.
"Some compilers support an option to turn recognition of trigraphs off, or disable trigraphs by default and require an option to turn them on"
GCC might be one of the latter. Although it should by default ignore with warning, but in this case the ignoring might be causing the compile error
Trigraphs are converted at a very early stage of compilation, and can even be replaced in string literals. This makes errors that arise from trigraph translations very hard to detect (worst off if you consider debugging using a log and you find the output in your source).
The warning you see will help you quickly spot a possible culprit to track the source of the bug. Basically it's warning you that something might not be as you think it is.

Compiler chosing prefix ++ when postfix is missing - who says?

When you define a prefix operator++ for your user defined type and you don't provide a postfix version, the compiler (in Visual C++ at least) will use the PREFIX version when your code calls the missing POSTFIX version.
At least it will give you a warning. But, my question is: Why doesn't it just give you an error for the undefined member function?
I have seen this first hand, and have seen it mentioned in another post and elsewhere, but I cannot find this in the actual C++ standard. My second and third questions are... Is it in the standard somewhere? Is this a Microsoft-specific handing of the situation?
Actually, In this case the MSVC behaves much more intelligently than GCC.
This is a MSVC compiler extension and the C++ standard explicitly allows for such an behavior.
C++ Standard:
Section 1.4/8:
A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so, however, they can compile and execute such programs.
In this case, MSVC appropriately diagnoses the problem that the postfix is not available and it specifically defines warnings,
Compiler Warning (level 1) C4620
Compiler Warning (level 1) C4621
Also, it provides you a facility to disable the MSVC specific extensions by using /Za. Overall, I would say this is one of the instances where MSVC actually behaves better than GCC.
It should be a Microsoft specific extension. Because, at least g++ is strict about prefix and postfix operators. Here is the demo link.
With integers, ++i is different from i++. For exampe i=5, y = ++i - y will be 6; y=i++ - y will be 5. Other types should function in the same manner. Therefore the behaviour differs between postfix and prefix.
It is a Microsoft thing and in my opinion the compilers implementation is incorrect.