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.
Related
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
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.
As far as I'm aware, my two options for handling stream errors are perror and stream exceptions. Both options are undesirable. Here's why:
perror
std::strerror returns an implementation-defined message. This message is not always useful on all systems
std::strerror is not thread-safe
The pointer returned by std::strerror can be invalidated
The C library is technically "deprecated" in C++. There's almost always a C++-ish equivalent. There's no reason why I should have to rely on POSIX and C when there's a potential C++ equivalent
stream exceptions
Exceptions are not appropriate for every program
While std::strerror can sometimes provide a useful error message, stream exceptions never provide a useful error message. With f.exceptions(f.failbit), for both failure to open a file or failure to extract, the exception thrown is std::ios_base::failure and the what() is "basic_ios::clear".
system_error
Replacing std::ios_base::failure with std::system_error produces exactly the same results. If we take a look at N2769: Detailed Reporting for Input/Output Library Errors (Revision 2), we can see why:
When throwing ios_base::failure exceptions, implementations are
encouraged to provide values of ec that identify the specific reason
for the failure. [Note - Errors arising from the operating
system would typically be reported as system_category errors with an
error value of the error number reported by the operating system.
Errors arising from within the stream library would typically be
reported as error_code(ioerrc::stream, iostream_category) -- end
note].
The above wording provides only normative encouragement for implementers to do the right thing, and thus relies on market forces
and the good intensions of implementers to produce results useful to
users. Anything stronger (such as changing "are encouraged to" to
"shall") would require much additional specification and is beyond the
scope of what the LWG can realistically tackle for C++0x.
The alternative is to potentially rely on a bulky third party library (I'm looking at you Boost) or to hand-roll it (which you never want to do unless you know what you're doing.) I'm looking for the C++ standard library way to do this. Is there any?
I do not agree with you on
perror et alii are member of C standard library and as such technically deprecated(*).
Well even on cplusplus.com if not an official documentation source, I see for errno:
C++11 expands the basic set of values required to be defined in this header... In C++, errno is always declared as a macro, but in C it may also be implemented as an int object with external linkage.
My understanding of those sentences is that errno is still considered in C++11!
I can even see later
Libraries that support multi-threading shall implement errno in a per-thread basis: With each thread having its own local errno. This is a requirement in libraries compliant with C11 and C++11 standards.
it means that even if strerror() is not thread-safe, errno is in any C++11 compliant implementation.
It is now up to you to use std::strerror in a synchronized function (for example protected with a mutex) to build a std::string if you like. But anyway, even if every documentation on strerror states that it uses a static buffer that could be overwritten (that's why Posix 1 defines strerror_r), I could not find any warning on perror not beeing thread safe.
(*) My opinion on that is that whenever OO and templates can give a nicer interface (iostream vs stdio.h or string vs. string.h), elements of the C library are replaced by others in C++ library. But when there is nothing to add (cerrno, cmath, csignal, etc.) the functions from C standard library are simply included in C++ one.
POSIX has strerror_r() and Windows has strerror_s(). Note that there have been several incompatible functions called strerror_r() out there, so use your feature-test macros.
Is an implementation allowed to issue a diagnostic message for a well-formed program?
For example some compilers issue a warning about unused expression result when compiling the following well-formed program:
int main() { 0; }
Are such compilers allowed to consider that warning a diagnostic message?
It's perfectly fine to issue a diagnostic, as long as the rules below are met in any corresponding scenario. §1.4/2:
Although this International Standard states only requirements on C ++
implementations, those requirements are often easier to understand if
they are phrased as requirements on programs, parts of programs, or
execution of programs. Such requirements have the following meaning:
If a program contains no violations of the rules in this International Standard, a conforming implementation shall, within
its resource limits, accept and correctly execute that program.
If a program contains a violation of any diagnosable rule or an occurrence of a construct described in this Standard as
“conditionally-supported” when the implementation does not support
that construct, a conforming implementation shall issue at least one
diagnostic message.
If a program contains a violation of a rule for which no diagnostic is required, this International Standard places no requirement on
implementations with respect to that program.
"Accepting" solely addresses the acknowledgment of the implementation that this is a well-formed program, not the absence of any diagnostics. After all, despite any warnings issued in the process, implementations still yield the object file you asked for.
However, there is one rule concerning templates that does require that there be no diagnostic issued; §14.6/8:
No diagnostic shall be issued for a template for which a valid
specialization can be generated.
An implementation can issue (1)any number of diagnostics it wants, as long as it does issue the required diagnostics.
It must accept correct programs, to the degree that it's able to,
C++14 §1.4/2:
” If a program contains no violations of the rules in this International Standard, a conforming imple-
mentation shall, within its resource limits, accept and correctly execute that program"
but it can issue diagnostics about it.
The C++ standard does not differentiate between error messages and warning messages, but this is a de facto standard. An error message means (by convention) that no binary is produced, because the problem is too severe. A warning message means (by convention) that there is a potential problem, but not a direct violation of language rules, and so a binary is produced unless there are also errors.
Sometimes the lines are a bit blurred, where implementations incorrectly but for pragmatic reasons accept invalid code, with only warnings or even no diagnostics. For new code one may therefore ask the compiler to treat every warning as an error, and aim for completely clean compiles. And as I understand it that's now absolutely not uncommon.
With some compilers, e.g. Visual C++, it can however be problematic, because the compiler issues too many silly-warnings, warnings about perfectly legitimate and non-problematic constructs. Then one has to somehow suppress those warnings. E.g. via #pragma directives, if possible, or by code rewrites.
Happily for Visual C++ there exists a header with such #pragma directives that turn off sillywarnings, compiled about five years ago from a community effort in the comp.lang.c++ Usenet group. And happily, for the community edition of Visual Studio 2015 there is an extension that provides a project template with that header included. These are both by me.
For the code in question,
int main() { 0; }
… instead of suppressing the warning, which generally is a useful one, you should rewrite the code to express your intent explicitly:
int main() { (void)0; }
The (void) cast tells the compiler that it's your intent to discard the value of that expression.
In the case of using this construct for an otherwise unused function argument, you can additionally declare an incomplete class of the same name, to prevent inadvertent use of the name:
(void)arg_name; struct arg_name;
But since it's unconventional it may trip up other programmers – with the compilers I use the error message for later use of the name is not exactly intuitive.
(1) Except as noted by Columbo in his answer, C++14 §14.6/8 “No diagnostic shall be issued for a template for which a valid specialization can be generated.”.
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.