Two VS2005 C++ compiler bugs in few simple lines of code...

I

Ivan Vecerina

Here's a relatively simple code snippet:


#include <memory>

class Base {
public:
Base();
virtual ~Base();
virtual void f(int a, char const* name);
};

class Sub : public Base {
public:
Sub();
virtual ~Sub();
// **PROBLEM 1** : incorrect warning
virtual void f(int a, char const* const name);
};

class Other { //NB: forgot to specify base class
public:
Other();
virtual ~Other();
virtual void f(int a, char const* const name);
};

std::auto_ptr<Base> factory()
{
// **PROBLEM 2** : this should be a compilation error
return std::auto_ptr<Base>( new Other() );
}


**PROBLEM 1** : VS2005 reports the following warning:
Warning 2 warning C4301: 'Sub::f': overriding virtual function only
differs from 'Base::f' by const/volatile qualifier
c:\dev\ivec_dev\ivec\render\image\imagelogger.cpp 23

But the added "top-level" const is not part of the function's signature,
so the code is perfectly legit.


**PROBLEM 2** : VS2005 generates invalid code
This should trigger a compilation error, because Other is
not a subclass of Base. Somehow this slips through,
and invalid code is generated (the pointer value somehow
gets garbled...). (compiler or library bug??)


Any luck to see those fixed in the upcoming service pack?
 
A

Andre Kaufmann

Ivan said:
Here's a relatively simple code snippet:
[...]
**PROBLEM 2** : VS2005 generates invalid code
This should trigger a compilation error, because Other is
not a subclass of Base. Somehow this slips through,
and invalid code is generated (the pointer value somehow
gets garbled...). (compiler or library bug??)

Seems to be a library bug. (?)

There's a constructor in the memory header file for auto_ptr
constructing a auto_ptr_ref object which accepts a void pointer. Since
void* matches all pointers it accepts all pointers and is converted back
to the pointer type of the auto_ptr object.

changing: auto_ptr_ref(void *_Right) into
auto_ptr_ref(_Ty *_Right) fixes the bug. Though I don't know what impact
this change may have on other code and why there's a non explicit
constructor with that proxy class argument accepting void pointers. (???)
Any luck to see those fixed in the upcoming service pack?

Don't know if it's already fixed in the SP1 Beta of VS2005. I'll give it
a try and will report the bug.

Andre
 
A

alexcohn

I don't know why you complain about the first warning. It does speak
exactly about the problem you've got. 'summary on MSDN page'
(http://msdn2.microsoft.com/en-us/library/bby1ahfc.aspx) shows the case
almost identical to yours. The C++ language has a dangerous feature of
treating "const int" and "int" formal parameters as different types.
But actually such parameters behave almost the same (unlike pointers:
int* vs. const int*). The warning is supposed to save you lots of hours
of investigation why a function that you intended to override in a
derived class was not overridden. I can assure you, it's a great help.
I experienced this problem with VC++ 6.0.
 
D

Doug Harrison [MVP]

I don't know why you complain about the first warning. It does speak
exactly about the problem you've got. 'summary on MSDN page'
(http://msdn2.microsoft.com/en-us/library/bby1ahfc.aspx) shows the case
almost identical to yours. The C++ language has a dangerous feature of
treating "const int" and "int" formal parameters as different types.

No, they are supposed to be considered the same type, and VC does consider
them the same in other contexts, such as in sets of overloaded functions.
BTW, the example in that article is bogus, because it does not demonstrate
the polymorphism (or lack thereof) it is apparently intended to
demonstrate. Here's a fixed version:

#include <stdio.h>

class Base {
public:
virtual void Func(const int i) {
puts("base");
}
};

class Derived : public Base {
public:
// Delete the following line to resolve.
void Func(int i) { puts("derived"); } // C4301

// Uncomment the following line to resolve.
// void Func(const int i) { puts("derived"); }
};

int main() {
Base B;
Derived D;

Base* p;

p = &B;
p->Func(0);

p = &D;
p->Func(0);
}

To see VC consider "int" and "const int" the same parameter type, uncomment
the second "Func" and leave the first one alone.
But actually such parameters behave almost the same (unlike pointers:
int* vs. const int*). The warning is supposed to save you lots of hours
of investigation why a function that you intended to override in a
derived class was not overridden. I can assure you, it's a great help.
I experienced this problem with VC++ 6.0.

But the function is supposed to be overridden. The warning alerts you to
the fact that it is not, so even though the warning is bogus, it at least
serves some purpose by alerting you to the compiler bug.
 
T

Tom Widmer [VC++ MVP]

Ivan said:
Here's a relatively simple code snippet:


#include <memory>

class Base {
public:
Base();
virtual ~Base();
virtual void f(int a, char const* name);
};

class Sub : public Base {
public:
Sub();
virtual ~Sub();
// **PROBLEM 1** : incorrect warning
virtual void f(int a, char const* const name);
};

class Other { //NB: forgot to specify base class
public:
Other();
virtual ~Other();
virtual void f(int a, char const* const name);
};

std::auto_ptr<Base> factory()
{
// **PROBLEM 2** : this should be a compilation error
return std::auto_ptr<Base>( new Other() );
}


**PROBLEM 1** : VS2005 reports the following warning:
Warning 2 warning C4301: 'Sub::f': overriding virtual function only
differs from 'Base::f' by const/volatile qualifier
c:\dev\ivec_dev\ivec\render\image\imagelogger.cpp 23

But the added "top-level" const is not part of the function's signature,
so the code is perfectly legit.

Why do you consider this a bug? The warning is perfectly correct in what
it says, and the code generated is correct. I suppose it is warning you
that your added const is a bit of a strange thing to add in a function
declaration, since it has the effect of making the parameter list look
different to the superclass function. If you do the same thing with a
definition (add top level parameter const), no warning is generated.
**PROBLEM 2** : VS2005 generates invalid code
This should trigger a compilation error, because Other is
not a subclass of Base. Somehow this slips through,
and invalid code is generated (the pointer value somehow
gets garbled...). (compiler or library bug??)

This is a truely horrendous bug. The situation is very bad - there is an
implicit conversion from *any* pointer type to auto_ptr<T>! It has come
around because of a missing "explicit" on the auto_ptr_ref(void*)
constructor, so it's a library bug.

I don't think the bug affects correct code, though I may be wrong - it
may well affect some of the auto_ptr corner cases.

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842

I can't believe it hasn't been fixed yet, since it makes a basic class
template of the standard library far too dangerous to use in VC2005!

Tom
 
D

Doug Harrison [MVP]

Why do you consider this a bug? The warning is perfectly correct in what
it says, and the code generated is correct.

Try the example I posted in another message. It demonstrates that
differences in top-level const cause the function not to be overridden.
That's a bug. The warning is actually wrong in several ways:

a.cpp(16) : warning C4301: 'Derived::Func': overriding virtual function
only differs from 'Base::Func' by const/volatile qualifier

The "only differs" bit makes it sound like it needs to differ by more than
that, which makes no sense. It incorrectly identifies the function as an
"overriding virtual function", when it doesn't override the base class
version. It also is not a (new) virtual function.
I suppose it is warning you
that your added const is a bit of a strange thing to add in a function
declaration, since it has the effect of making the parameter list look
different to the superclass function.

So does using a different name for a parameter, but that doesn't generate a
warning. Differences in top-level const should have exactly the same effect
on the type of the function: none.
 
T

Tom Widmer [VC++ MVP]

Doug said:
Try the example I posted in another message. It demonstrates that
differences in top-level const cause the function not to be overridden.
Yikes.

That's a bug.

Definitely! I thought it was just an overzealous warning, not an
indication that the compiler was not considering Sub::f an override of
Base::f.

The warning is actually wrong in several ways:
a.cpp(16) : warning C4301: 'Derived::Func': overriding virtual function
only differs from 'Base::Func' by const/volatile qualifier

The "only differs" bit makes it sound like it needs to differ by more than
that, which makes no sense.

That's not the only way of interpreting it though. Either way, it would
alert you to the fact that Derived::Func is an override for Base::Func,
despite the top-level const that's been added. This may or may not have
been what the code writer intended.

It incorrectly identifies the function as an
"overriding virtual function", when it doesn't override the base class
version.

Well, in that respect, the warning text is correct, since it is
*supposed* to override the base, and a (separate?) compiler bug means it
doesn't.

It also is not a (new) virtual function.

Not sure what you mean there - it certainly is a virtual function.
So does using a different name for a parameter, but that doesn't generate a
warning. Differences in top-level const should have exactly the same effect
on the type of the function: none.

I agree, but if it were only a warning (and the compiler were making
Sub::Foo an override of Base::foo), I would not consider it a bug, but
rather an overzealous warning.

Tom
 
D

Doug Harrison [MVP]

Not sure what you mean there - it certainly is a virtual function.

We may be mixing up our examples. If you extend the example I posted to
derive a class from Derived, you can demonstrate that the function in
Derived is not virtual. As it is not declared virtual, this makes some
sense, because due to the compiler bug, it doesn't override the base class
function.
I agree, but if it were only a warning (and the compiler were making
Sub::Foo an override of Base::foo), I would not consider it a bug, but
rather an overzealous warning.

I'd rather it warn about differences in default parameter values, or using
default parameters in virtual functions at all. :)

Here is an updated example that derives a new class Derived2 from Derived
and declares all its functions virtual:

#include <stdio.h>

class Base {
public:
virtual void Func(int i) {
puts("base");
}
};

class Derived : public Base {
public:
virtual void Func(const int i) { puts("derived"); }
};

class Derived2 : public Derived {
public:
//virtual void Func(int i) { puts("derived2"); }
virtual void Func(const int i) { puts("derived2"); }
};

int main() {
Derived2 d2;
Base* pBase = &d2;
Derived* pDerived = &d2;

pBase->Func(2);
pDerived->Func(2);
}

If you play around with this, you'll see the compiler considers "int" and
"const int" distinguishable for overriding purposes but not for
overloading, when they should be indistinguishable for both.
 
B

Ben Voigt

Ivan Vecerina said:
Here's a relatively simple code snippet:


#include <memory>

class Base {
public:
Base();
virtual ~Base();
virtual void f(int a, char const* name);
};

class Sub : public Base {
public:
Sub();
virtual ~Sub();
// **PROBLEM 1** : incorrect warning
virtual void f(int a, char const* const name);
};

class Other { //NB: forgot to specify base class
public:
Other();
virtual ~Other();
virtual void f(int a, char const* const name);
};

std::auto_ptr<Base> factory()
{
// **PROBLEM 2** : this should be a compilation error
return std::auto_ptr<Base>( new Other() );
}


**PROBLEM 1** : VS2005 reports the following warning:
Warning 2 warning C4301: 'Sub::f': overriding virtual function only
differs from 'Base::f' by const/volatile qualifier
c:\dev\ivec_dev\ivec\render\image\imagelogger.cpp 23

But the added "top-level" const is not part of the function's signature,
so the code is perfectly legit.

Looks like what I reported here:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100917
 
A

alexcohn

To Ben Voigt: cool, the resolution there looks encouraging. The bug has
been there at least since VC 6...
 

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

Top