"extra qualification" errors. How warranted by the Standard? - c++

This similar ill-fated question
got comments and short answers, before it was closed, to the effect: Because that's
how the language is defined. Here I am asking for the evidence within the
C++ Standard that it is so defined.
gcc 4.8.1 and clang 3.3 alike, with default diagnostic options or stricter,
give errors for extra qualification or explicit qualification on
code such as:
struct x
{
int x::i; // Error: gcc/clang: "extra"
};
int ::y; // Error: gcc: "explicit", clang: "extra"
gcc has diagnosed such errors since v4.1. But popular compilers are not
unanimous about these errors. MSVC++ 2012 (Nov CTP)
gives an error at int ::y; but even with /Wall, gives no diagnostic at all
int x::i; - the kind of case that the ill-fated questioner was raising -
and that difference suggests deliberation by the MS compiler writers.
How are these errors warranted by the Standard, if they are? References to the C++11
Standard will suffice.
An answer might be "They follow from grammar". In that case,
please try to show how they follow from the grammar and feel free to use
the Standard's grammatical classifications. I have a copy and will re-read it
to understand the explanation.

A qualified name in C++ always must refer to a previously declared name. This is specified in clause 8.3 and 3.4.3.2.
You cannot firstly declare a variable or member by using a qualified name - it will end up in a "cannot resolve identifier"-liky compiler error. Such qualifiers are designed to be used for redeclaration. Hence the requirement that these names must find previously declared entities.

It is a bug in the Microsoft compiler to allow x::i within the definition of struct x. There are several of these errors in the MSVC front end, and have been reported to Microsoft but they get closed without being fixed (see similar but different error reported here: https://connect.microsoft.com/VisualStudio/feedback/details/783433/c-compiler-accepts-explicit-constructor-call#details and https://connect.microsoft.com/VisualStudio/feedback/details/794504/keyword-struct-before-constructor-name).
The reason it is invalid is because you are both trying to declare a variable int i and provide a scope using x::i. The scope of the variable is dictated by where it is declared, so trying to declare something with a scope specification is trying to declare it somewhere else, which is invalid.

Related

C++ mark a function as experimental/not fully implemented

I have a function I will need to leave partially implemented for a variety of reasons and I want to prevent future users (read as me in the future when I have forgotten that I did this) to know the function is incomplete, buggy and untested.
Option n1 is merely adding a comment // Warning this thing is partially implemented and will break randomly
This however won't create compile time warnings so, I am not a fan.
Option n2 is to use [[deprecated("reason")]] which has the advantage of raising compile warnings but its misleading, the function wasn't deprecated it's actually the opposite of deprecation, it's a WIP and will perhaps one day be fully implemented.
Are there alternatives?
The [[deprecated]] attribute is exactly what this is for (emphasis mine) :
https://en.cppreference.com/w/cpp/language/attributes
[deprecated]
[deprecated("reason")]
indicates that the use of the name or entity declared with this attribute is allowed, but discouraged for some reason
You can still use the function, you just get a warning message that you shouldn't rely on its use.
Caveat: MSVC breaks the standard and emits a compiler error (due to SDL flag being turned on by default) instead of a warning.
The only thing in standard C++ for this is the [[deprecated("message")]] attribute.
GNU has a non-standard Function Attribute for warning messages:
warning ("message")
If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, a warning which will include message will be diagnosed. This is useful for compile time checking, especially together with __builtin_constant_p and inline functions. While it is possible to define the function with a message in .gnu.warning* section, when using this attribute the problem will be diagnosed earlier and with exact location of the call even in presence of inline functions or when not emitting debugging information.

Why does gcc warn about decltype(main()) but not clang?

Take the following code:
int main()
{
decltype(main()) x = 0;
return x;
}
gcc complains:
main.cpp: In function 'int main()':
main.cpp:8:19: warning: ISO C++ forbids taking address of function '::main' [-Wpedantic]
decltype(main()) x = 0;
^
main.cpp:8:19: warning: ISO C++ forbids taking address of function '::main' [-Wpedantic]
but not clang. So what about decltype(main()) raises this error? How does decltype take the address of main?
GCC's diagnostic might not be correctly phrased in this case, because decltype doesn't need to know the address of main; it only needs to know its type. However, the warning is based on the following from the standard (§3.6.1/3):
The function main shall not be used within a program.
I suppose GCC interprets this to mean that you can't even use it in an unevaluated expression.
Clang (version 3.4 anyway) appears to not implement this rule at all, even if I turn on all the flags I can think of and even if main calls itself recursively. That's why it doesn't give you a warning.
This topic actually came up recently in the undefined behaviour study group discussion list in the thread What does "The function main shall not be used within a program" mean?. It does not come up right away but here is where it starts in the thread with the following statement:
I don't think decltype(main()) is an odr-use, or
sizeof(decltype(main)).
a very abbreviated set of responses looks like this:
True, I just don’t see what utility those would be. You might mean
sizeof(decltype(&main)) in the latter case.
I think the most common non-ODR use of main would be defining it after
a forward declaration, and now Steven Clamage has clarified that
should be ill-formed. The broader definition of “use” as being a
result of name lookup without reference to ODR looks correct now.
and:
C++98's mention of 'use' had a cross-reference to 3.2 [basic.def.odr].
C++11 no longer has the cross-reference, and was not changed to say
'odr-use', so I expect it means any use.
and so it would seem that the interpretation of section 3.6.1 Main function which says:
The function main shall not be used within a program. [...]
means any use even in unevaluated contexts and so gcc is correct here to produce an error although the message itself does not seem to make sense.
Update
It is interesting and instructive to note that the original proposal: N3154 to fix Defect report 1109 would have changed 3.6.1 to:
The function main shall not be odr-used (3.2) within a program. ...
which would have allowed the decltype example but was amended when accepted and we can see that the new proposal: N3214 changed to what we have today:
The function main shall not be used within a program
which would strongly indicate the opinion in the UB mailing list that any use of main is ill-formed is indeed correct.

Why is gcc's option "-Wstrict-prototypes" not valid for C++?

Here is a warning I, and lots of people out there on the web, see when running gcc on C++ code:
cc1plus: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
The warning text is very clear: 'C++' is not in the set [Ada/C/ObjC ], so I have no question at all about why gcc gives this warning when compiling C++ code. (FYI the reason we have this flag turned on in spite of having C++ code is because it's mostly C code, we have chosen a strict (high level of) warning options list, but we've added a bit of C++ code.
My question is: Why isn't this warning valid for C++?
The gcc documentation for the warning option, from http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Warning-Options.html, is:
-Wstrict-prototypes (C and Objective-C only) Warn if a function is declared or defined without specifying the argument types. (An
old-style function definition is permitted without a warning if
preceded by a declaration which specifies the argument types.)
Now I just know I'm forgetting something obvious about C++, but doesn't C++ also require specifying argument types for functions in a prototype? True that those function prototypes are often in class declarations because the functions are often member functions, but aren't prototypes nevertheless required? Or even if they're just good practice, then why wouldn't gcc offer support by this option? Or if not, by a parallel option for C++?
I suppose it's becuase C++ requires strict prototypes as part of the language, so the option is superfluous. Why that makes it so GCC needs to complain about it is beyond me.
I have that option set in my build script for small sample/test C or C++ programs, and the warning kind of irritates me - it seems like there's no reason to warn just because the default behavior for a language is what I'm asking for. But it's there, so one day when it irritates me enough I'll fix my script to not bother with that option for C++ builds.
It's required by the C++ standard so there's no meaning of turning it on or off: It's always on in the language.
It is implicit in C++ because declaring/defining a function without specifying the argument types is illegal C++ by the standard (yes, this is one of the differences between C and C++ which makes C++ not a true superset).
This is legal C99, but not legal C++03:
void foo(x, y)
int x;
char *y;
{
// ...
}
GCC gives a warning for this in C if compiled with -Wstrict-prototypes.
Another interesting special case:
extern int foo();
By C semantics this declaration specifies an incomplete type for foo, as a function where the number and type of arguments remains unspecified. This is nevertheless a fully valid declaration in C99/C11; however -Wstrict-prototypes forces a warning for this valid declaration in C.
By C++ semantics, this declaration specifies a complete type for foo, as a function that takes no arguments (i.e., it is equivalent to extern int foo(void)). Hence -Wstrict-prototypes is not relevant for this case in C++.

What is wrong with this use of offsetof?

I'm compiling some c++ code in MinGW GCC 4.4.0, and getting warnings with the following form...
warning: invalid access to non-static data member '<membername>' of NULL object
warning: (perhaps the 'offsetof' macro was used incorrectly)
This problem seems familiar - something I've tried to resolve before and failed, I think, but a while ago. The code builds fine in Visual C++, but I haven't built this particular code recently in any other compiler.
The problem code is the following template...
template<typename T>
class c_Align_Of
{
private:
struct c_Test
{
char m_Char;
T m_Test;
};
public:
enum { e_Align = offsetof (c_Test, m_Test) };
};
Obviously I can probably use some conditional compilation to use compiler-specific functions for this, and I believe C++0x will (at long last) make it redundant. But in any case, I cannot see anything wrong with this use of offsetof.
Very pedantically, it's possible that because the T parameter types are sometimes non-POD, so GCC classes c_Test as non-POD and complains (and complains and complains - I'm getting nearly 800 lines of these warnings).
This is naughty by the strict wording of the standard, since non-POD types can break offsetof. However, this kind of non-POD shouldn't be a problem in practice - c_Test will not have a virtual table, and no run-time trickery is needed to find the offset of m_Test.
Besides, even if c_Test had a virtual table, GCC implements the offsetof macro using an intrinsic that is always evaluated at compile-time based on the static layout of that particular type. Providing a tool then whining (sorry, warning) every time it's used just seems silly.
Also, I'm not the only person around here who does this kind of thing...
Answer to legit-uses-of-offsetof question
I do remember having an issue with offsetof for this kind of reason, but I don't think the problem was this template.
Any ideas?
Oops...
The issue is with the c_Test struct being non-POD due to the T type being non-POD. Here's a quote from the GCC manual...
-Wno-invalid-offsetof (C++ and Objective-C++ only)
Suppress warnings from applying the
‘offsetof’ macro to a non-POD type.
According to the 1998 ISO C++
standard, applying ‘offsetof’ to a
non-POD type is undefined. In existing
C++ implementations, however,
‘offsetof’ typically gives meaningful
results even when applied to certain
kinds of non-POD types. (Such as a
simple ‘struct’ that fails to be a POD
type only by virtue of having a
constructor.) This flag is for users
who are aware that they are writing
nonportable code and who have
deliberately chosen to ignore the
warning about it.
The restrictions on ‘offsetof’ may be
relaxed in a future version of the C++
standard.
My problem is that almost all my T types have constructors, and are therefore classed as non-POD. I ignored this point as irrelevant earlier - and of course it should be irrelevant for offsetof in principle. The trouble is that the C++ standard uses the one POD vs. non-POD classification even though there are a number of distinct ways to be non-POD, and the compiler is correct to warn about non-standards-compliant use by default.
My solution for the moment will be the option above to suppress the warning - now I just need to figure out how to tell cmake to use it.

void, VOID, C and C++

I have the following code:
typedef void VOID;
int f(void);
int g(VOID);
which compiles just fine in C (using gcc 4.3.2 on Fedora 10). The same code compiled as C++ gives me the following error:
void.c:3: error: ‘<anonymous>’ has incomplete type
void.c:3: error: invalid use of ‘VOID’
Now, this is something in external library and I would like the owner to fix that problem. So I have a question - does C++ standard forbids this construct? Could you give me a pointer/citation? The only thing I can recall is that function declaration with (void) to signal empty parameter list is deprecated in C++, but I don't understand why typedefed VOID does not work.
Yes, as far as i know the second declaration is invalid in C++ and C89, but it is valid in C99.
From The C99 draft, TC2 (6.7.5.3/10):
The special case of an unnamed parameter of type void as the only item in the list
specifies that the function has no parameters.
It's explicitly talking about the type "void", not the keyword.
From The C++ Standard, 8.3.5/2:
If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list.
That it means the actual keyword with "void", and not the general type "void" can also be seen from one of the cases where template argument deduction fails (14.8.2/2):
Attempting to create a function type in which a parameter has a type of void.
It's put clear by others, notable in one core language issue report here and some GCC bugreports linked to by other answers.
To recap, your GCC is right but earlier GCC versions were wrong. Thus that code might have been successfully compiled with it earlier. You should fix your code, so that it uses "void" for both functions, then it will compile also with other compilers (comeau also rejects the second declaration with that "VOID").
gcc bugs. Edit: since it wasn't clear enough, what I meant was gcc 4.3.2 was compiling it due to bugs. See #32364 and #9278.
I just put your code in a .cpp file, and it compiled with no problems in VS2005, SUSE, Redhat, and Solaris, so I guess your specific gcc version does not approve of this.
Gal