Weird C++ Compiler Ignores Errors

I

Immortal Nephi

C++ Compiler looks weird. It will succeed to compile if your source
code has some errors. I wrote an example of generic class. I
commented Errors.Print() in the main function body. Errors.Print()
has two variables _x and _y, but class definition only shows two
variables x and y.
Go ahead and try to compile. Read my comments below.

template< typename T >
class IgnoreErrors
{
public:
IgnoreErrors() : x( 1 ), y( 2 ) {}
~IgnoreErrors() {}

void Print();

T x;
T y;
};

template< typename T >
void IgnoreErrors< T >::print()
{
_x = 5;
_y = 10;
}

int main()
{
IgnoreErrors<int> Errors;
// Errors.Print();

return 0;
}
------ Build started: Project: Errors, Configuration: Debug Win32
------
Compiling...
main.cpp
Linking...
Embedding manifest...
Build log was saved at "file://c:\My Projects\Errors\Errors\Debug
\BuildLog.htm"
Errors - 0 error(s), 0 warning(s)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped
==========

Now, you uncomment Errors.Print(). C++ Compiler will fail to compile
and report two _x and _y undeclared identifier variables. You correct
to rename by removing underscore before variable name. Then, try to
compile. C++ Compiler reports no errors.
Do you have explanation why C++ Compiler ignores errors if you don’t
declare and define Errors.Print() in main function body?

------ Build started: Project: Errors, Configuration: Debug Win32
------
Compiling...
main.cpp
c:\my projects\errors\errors\main.cpp(20) : error C2065: '_x' :
undeclared identifier
c:\my projects\errors\errors\main.cpp(19) : while compiling
class template member function 'void IgnoreErrors<T>::print(void)'
with
[
T=int
]
c:\my projects\errors\errors\main.cpp(27) : see reference to
class template instantiation 'IgnoreErrors<T>' being compiled
with
[
T=int
]
c:\my projects\errors\errors\main.cpp(21) : error C2065: '_y' :
undeclared identifier
Build log was saved at "file://c:\My Projects\Errors\Errors\Debug
\BuildLog.htm"
Errors - 2 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped
==========
 
A

Alf P. Steinbach

* Immortal Nephi:
Do you have explanation why C++ Compiler ignores errors if you don’t
declare and define Errors.Print() in main function body?

You're defining a class template.

Any concrete instantiation is checked as rigorously as any other C++ code, but
the template itself is only subject to some very cursory checks (including
syntax) since essentially nothing is known about the template parameters.

This has the advantage of making templates more useful since the template itself
needs only conform to a sort of duck typing, but it also has the disadvantage of
not becoming aware of many errors until you instantiate the template.


Cheers & hth.,

- Alf
 
J

Jonathan Lee

        Do you have explanation why C++ Compiler ignores errors if you don’t
declare and define Errors.Print() in main function body?

Compilers don't instantiate template functions that are never used.
So the error is never detected. I'm sure the compiler doesn't check
anything beyond the fact that the code parses as C++.

--Jonathan
 
T

tonydee

        C++ Compiler looks weird.  It will succeed to compile if your source
code has some errors.  I wrote an example of generic class.  I
commented Errors.Print() in the main function body.  Errors.Print()
has two variables _x and _y, but class definition only shows two
variables x and y.
        Go ahead and try to compile.  Read my comments below.

[...snip...]
template< typename T >
void IgnoreErrors< T >::print()
{
        _x = 5; // NO SUCH VARIABLES!
        _y = 10;
}

This is actually extremely useful! It means that a templated class
can provide services to some instantiations, without breaking the
compilation for incompatible instantiations, as long as the client
doesn't try to use them. You could (seemingly are) say "but I
published what seemed a finished library only to find a compile-time
error when the client tried to use it"... true! So, write test cases
to exercise your code. You need to do that to cover myriad classes of
other errors anyway (run-time, performance, negative test cases).

Cheers,
Tony
 
P

Paul Bibbings

Immortal Nephi said:
C++ Compiler looks weird. It will succeed to compile if your source
code has some errors. I wrote an example of generic class. I
commented Errors.Print() in the main function body. Errors.Print()
has two variables _x and _y, but class definition only shows two
variables x and y.
Go ahead and try to compile. Read my comments below.

template< typename T >
class IgnoreErrors
{
public:
IgnoreErrors() : x( 1 ), y( 2 ) {}
~IgnoreErrors() {}

void Print();

T x;
T y;
};

template< typename T >
void IgnoreErrors< T >::print()
{
_x = 5;
_y = 10;
}

int main()
{
IgnoreErrors<int> Errors;
// Errors.Print();

return 0;
}
------ Build started: Project: Errors, Configuration: Debug Win32
------
Compiling...
main.cpp
Linking...
Embedding manifest...
Build log was saved at "file://c:\My Projects\Errors\Errors\Debug
\BuildLog.htm"
Errors - 0 error(s), 0 warning(s)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped
==========

Now, you uncomment Errors.Print(). C++ Compiler will fail to compile
and report two _x and _y undeclared identifier variables. You correct
to rename by removing underscore before variable name. Then, try to
compile. C++ Compiler reports no errors.
Do you have explanation why C++ Compiler ignores errors if you don¡¯t
declare and define Errors.Print() in main function body?

Others have discussed why your compiler (clearly VC++) does not diagnose
an error when Errors.Print() is commented, on the grounds that a class
member function is not instantiated until its definition is effectively
`required'. I would agree that the latter is the case, but that it
doesn't apply here; that this `error' should, in fact, be diagnosed on
other grounds.

My reasoning is that, in the the definition of IgnoreErrors, _x and _y
are not dependant names. As such they are subject to `point of
definition', and not `point of instantiation', checking. At the point
of definition no _x nor _y is in scope and no instantation is required
to diagnose this as an error.

The benefits of non-instantiation of a definition where that definition
is not required, as has been discussed, would only be applicable where
_x and _y were dependant names, as in, for example:

template< typename T >
void IgnoreErrors< T >::print()
{
T::_x = 5;
T::_y = 10;
}

In support of this, without being immediately able to reference the
relevant points in the standard, I should add that gcc-4.4.3 fails the
code that VC++ accepts:

11:41:14 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $i686-pc-cygwin-gcc-4.4.3 -c
ignore_errors.cpp
ignore_errors.cpp: In member function ¡®void IgnoreErrors<T>::print()¡¯:
ignore_errors.cpp:19: error: ¡®_x¡¯ was not declared in this scope
ignore_errors.cpp:20: error: ¡®_y¡¯ was not declared in this scope

as does Comeau (http://www.comeaucomputing.com/tryitout/):

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 19: error: identifier "_x" is undefined
_x = 5;
^

"ComeauTest.c", line 20: error: identifier "_y" is undefined
_y = 10;
^

2 errors detected in the compilation of "ComeauTest.c".
In strict mode, with -tused, Compile failed
Hit the Back Button to review your code and compile options.
Compiled with C++0x extensions DISabled.

Regards

Paul Bibbings
 
M

Michael Tsang

Paul said:
Others have discussed why your compiler (clearly VC++) does not diagnose
an error when Errors.Print() is commented, on the grounds that a class
member function is not instantiated until its definition is effectively
`required'. I would agree that the latter is the case, but that it
doesn't apply here; that this `error' should, in fact, be diagnosed on
other grounds.

My reasoning is that, in the the definition of IgnoreErrors, _x and _y
are not dependant names. As such they are subject to `point of
definition', and not `point of instantiation', checking. At the point
of definition no _x nor _y is in scope and no instantation is required
to diagnose this as an error.

The benefits of non-instantiation of a definition where that definition
is not required, as has been discussed, would only be applicable where
_x and _y were dependant names, as in, for example:

template< typename T >
void IgnoreErrors< T >::print()
{
T::_x = 5;
T::_y = 10;
}

In support of this, without being immediately able to reference the
relevant points in the standard, I should add that gcc-4.4.3 fails the
code that VC++ accepts:

11:41:14 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $i686-pc-cygwin-gcc-4.4.3 -c
ignore_errors.cpp
ignore_errors.cpp: In member function ‘void IgnoreErrors<T>::print()’:
ignore_errors.cpp:19: error: ‘_x’ was not declared in this scope
ignore_errors.cpp:20: error: ‘_y’ was not declared in this scope

as does Comeau (http://www.comeaucomputing.com/tryitout/):

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 19: error: identifier "_x" is undefined
_x = 5;
^

"ComeauTest.c", line 20: error: identifier "_y" is undefined
_y = 10;
^

2 errors detected in the compilation of "ComeauTest.c".
In strict mode, with -tused, Compile failed
Hit the Back Button to review your code and compile options.
Compiled with C++0x extensions DISabled.
Have you reported the bug yet?
 
Ö

Öö Tiib

Have you reported the bug yet?


Standard contains an explicit notation that "no diagnostic is
required" in 14.7. Example given there does not even parse:

int j;
template<class T> class X {
// ...
void f(T t, int i, char* p)
{
t = i; // diagnosed if X::f is instantiated
// and the assignment to t is an error
p = i; // may be diagnosed even if X::f is
// not instantiated
p = j; // may be diagnosed even if X::f is
// not instantiated
}
void g(T t) {
+; //may be diagnosed even if X::g is
// not instantiated
}
};

That "+;" certainly does not parse still it only "may be diagnosed".
So not diagnosing is not a bug.
 
P

Paul Bibbings

Öö Tiib said:
Standard contains an explicit notation that "no diagnostic is
required" in 14.7.

[Note: the reference for ISO/IEC 14882: 2003 is 14.6/7.]

I had managed to miss the "no diagnostic required." I am assuming that
the relevant section is (from 14.6/7):

"If no valid specialization can be generated for a template
definition, and that template is not instantiated, the templated
definition is ill-formed, no diagnostic is required."

What this leads me on to is what that actually means in terms of the
correctness of the program (in this instance, the program given in
the original post by the OP).

1.4/2 [intro.compliance] states:
"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."

At this point the (surely necessary) `legalese' begins to escape me. To
my reading, there appears to be (or, at least, I hear) an implicit
"whatsoever" after "places no requirement." To me this appears to be
saying, in relation to the OP's original code, that as it was accepted
without diagnostic (not being required to do so), it nevertheless rendered
the whole program, in so doing, effectively of no concern in terms of
the standard; what, in my part of the world, we'd translate to "you're
on your own, mate. Might as well be written in Pascal, for all I care!"

Would that be a fair reading, or is my legalese as bad as I think it
might be?

Regards

Paul Bibbings
 
P

Paul Bibbings

Michael Tsang said:
Have you reported the bug yet?

I don't think that I'd ever viewed this as a bug, in the sense of
program behaviour unexpected against what was intended. On the basis of
the assumption (as seems clear from the compiler output in the OP's
original post) that the compiler in question is some version of VC++,
then I think that it would be fair to say that there has been a long
history of debate about Microsoft's implementation - or should we say
/non/-implementation - of Two Phase Lookup. The OP didn't say which
version s/he was using, but it wouldn't have surprised me even to hear
that it was 2010. Not that I'm wanting to knock Microsoft for that. In
responses that I have read they clearly have strong business reasons in
terms of supporting an existing client base and not breaking existing
code.

Having said that, however, if you write code that does leverage TPL
fully, and which complies with the finer expectations of that, then you
will at least not get a complaint out of VC for doing so. Doing it VC's
way, however, does pretty much tie you in, or else gives you a major
porting concern when you come to look beyond that one implementation.

Regards

Paul Bibbings
 
Ö

Öö Tiib

Öö Tiib said:
Standard contains an explicit notation that "no diagnostic is
required" in 14.7.

[Note: the reference for ISO/IEC 14882: 2003 is 14.6/7.]

I had managed to miss the "no diagnostic required."  I am assuming that
the relevant section is (from 14.6/7):

   "If no valid specialization can be generated for a template
   definition, and that template is not instantiated, the templated
   definition is ill-formed, no diagnostic is required."


Yes, i messed up the numbers, thanks for correcting.

What this leads me on to is what that actually means in terms of the
correctness of the program (in this instance, the program given in
the original post by the OP).

1.4/2 [intro.compliance] states:
      "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."

At this point the (surely necessary) `legalese' begins to escape me.  To
my reading, there appears to be (or, at least, I hear) an implicit
"whatsoever" after "places no requirement."  To me this appears to be
saying, in relation to the OP's original code, that as it was accepted
without diagnostic (not being required to do so), it nevertheless rendered
the whole program, in so doing, effectively of no concern in terms of
the standard; what, in my part of the world, we'd translate to "you're
on your own, mate. Might as well be written in Pascal, for all I care!"

Would that be a fair reading, or is my legalese as bad as I think it
might be?

That standardese means basically that it is possible that someone evil
gains something from that undefined behavior. For example infects your
computer running that program with evil .jpg and gains control over
it. Standard has washed its hands then and also the hands of
implementations that translated the program by standard. It is
standards way to say that "BLA BLA NO WARRANTY BLA BLA NO
MERCHANTABILITY BLA BLA NO PARTICULAR PURPOSE."
 
P

Paul Bibbings

Öö Tiib said:
Öö Tiib said:
Standard contains an explicit notation that "no diagnostic is
required" in 14.7.

[Note: the reference for ISO/IEC 14882: 2003 is 14.6/7.]

I had managed to miss the "no diagnostic required."  I am assuming that
the relevant section is (from 14.6/7):

"If no valid specialization can be generated for a template
definition, and that template is not instantiated, the templated
definition is ill-formed, no diagnostic is required."


Yes, i messed up the numbers, thanks for correcting.

What this leads me on to is what that actually means in terms of the
correctness of the program (in this instance, the program given in
the original post by the OP).

1.4/2 [intro.compliance] states:
"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."

At this point the (surely necessary) `legalese' begins to escape me. To
my reading, there appears to be (or, at least, I hear) an implicit
"whatsoever" after "places no requirement." To me this appears to be
saying, in relation to the OP's original code, that as it was accepted
without diagnostic (not being required to do so), it nevertheless rendered
the whole program, in so doing, effectively of no concern in terms of
the standard; what, in my part of the world, we'd translate to "you're
on your own, mate. Might as well be written in Pascal, for all I care!"

Would that be a fair reading, or is my legalese as bad as I think it
might be?

That standardese means basically that it is possible that someone evil
gains something from that undefined behavior. For example infects your
computer running that program with evil .jpg and gains control over
it. Standard has washed its hands then and also the hands of
implementations that translated the program by standard. It is
standards way to say that "BLA BLA NO WARRANTY BLA BLA NO
MERCHANTABILITY BLA BLA NO PARTICULAR PURPOSE."

Now, you have brought in the term `undefined behavior'. Is that what we
have here? The relevant sections as they have been traced back from
§14.6/7 do not actually use the term.

§1.3.12 [defns.undefined] has, for undefined behavior:
"behavior, such as might arise upon use of an erroneous program
construct or erroneous data, for which this International Standard
imposes no requirements. Undefined behavior may also be expecte when
this International Standard omits the description of any explicit
definition of behavior. ..."

It certainly appears that this definition of undefined behavior uses the
same (or similar) terms to those used in §1.4/2, quoted above.

If so, the conclusion would then appears to be that, in compiling the
OP's original code, VC++ was invoking undefined behaviour and/or, at the
very least, exhibiting Standards non-compliance; that, although I was
wrong in my original analysis to suggest that "this `error' should, in
fact, be diagnosed on other grounds," it is, nonetheless, an error on
the part of VC++.

If this is how it is, does this generalize out? Do *all* uses of the
phrase "no diagnostic required" instantly impart Standard non-compliance
to the code in question, and perhaps also undefined behavior?

Regards

Paul Bibbings
 
Ö

Öö Tiib

Tiib said:
Standard contains an explicit notation that "no diagnostic is
required" in 14.7.
[Note: the reference for ISO/IEC 14882: 2003 is 14.6/7.]
I had managed to miss the "no diagnostic required." I am assuming that
the relevant section is (from 14.6/7):
   "If no valid specialization can be generated for a template
   definition, and that template is not instantiated, the templated
   definition is ill-formed, no diagnostic is required."
Yes, i messed up the numbers, thanks for correcting.
What this leads me on to is what that actually means in terms of the
correctness of the program (in this instance, the program given in
the original post by the OP).
1.4/2 [intro.compliance] states:
    "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."
At this point the (surely necessary) `legalese' begins to escape me. To
my reading, there appears to be (or, at least, I hear) an implicit
"whatsoever" after "places no requirement." To me this appears to be
saying, in relation to the OP's original code, that as it was accepted
without diagnostic (not being required to do so), it nevertheless rendered
the whole program, in so doing, effectively of no concern in terms of
the standard; what, in my part of the world, we'd translate to "you're
on your own, mate. Might as well be written in Pascal, for all I care!"
Would that be a fair reading, or is my legalese as bad as I think it
might be?
That standardese means basically that it is possible that someone evil
gains something from that undefined behavior. For example infects your
computer running that program with evil .jpg and gains control over
it. Standard has washed its hands then and also the hands of
implementations that translated the program by standard. It is
standards way to say that "BLA BLA NO WARRANTY BLA BLA NO
MERCHANTABILITY BLA BLA NO PARTICULAR PURPOSE."

Now, you have brought in the term `undefined behavior'.  Is that what we
have here?  The relevant sections as they have been traced back from
14.6/7 do not actually use the term.

For me the difference between "ill-formed, no diagnostic is required"
and "undefined behavior" is next to none.

"no diagnostic is required" is slightly worse news since it clearly
states that there is a defect made by developer (no doubt there) that
developer must diagnose himself on platforms that do not diagnose it
and such platforms are legal.

"undefined behavior" means that something may happen but standard
refuses to say what it is. Results of some "undefined behavior"s are
predictable with most implementations. Implementations however may
freely change the results (or make them less predictable) with other
compilation options (or with next version or with service patch to
current version) and keep being standard conformant.

Both are about equally bad news to developer who has to maintain code
that contains such things.
If so, the conclusion would then appears to be that, in compiling the
OP's original code, VC++ was invoking undefined behaviour and/or, at the
very least, exhibiting Standards non-compliance; that, although I was
wrong in my original analysis to suggest that "this `error' should, in
fact, be diagnosed on other grounds," it is, nonetheless, an error on
the part of VC++.

VC++ did not diagnose something that it is not required to diagnose.
No error done by VC++. Possibly it is even described what it does on
some page of MSDN. OP is required to diagnose it by other means and
not rely on VC, since it is ill formed code.
If this is how it is, does this generalize out?  Do *all* uses of the
phrase "no diagnostic required" instantly impart Standard non-compliance
to the code in question, and perhaps also undefined behavior?

Yes, all uses of it are about violations of something that shall be
otherwise in C++ code to make that code correct.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top