This appendix lists the warning and error messages produced by the Watcom C++ compilers. Diagnostic messages are issued during compilation and execution.
The messages listed in the following sections contain references to symbols that represent strings that are substituted by the Watcom C++ compilers to make the error message more exact:
The messages are ordered according to their numbers.
Use the following table to find a message quickly:000-099 | 100-199 | 200-299 | 300-399 | 400-499 | 500-599 | 600-699 | 700-715 |
---|---|---|---|---|---|---|---|
000 | 100 | 200 | 300 | 400 | 500 | 600 | 700 |
010 | 110 | 210 | 310 | 410 | 510 | 610 | 710 |
020 | 120 | 220 | 320 | 420 | 520 | 620 | |
030 | 130 | 230 | 330 | 430 | 530 | 630 | |
040 | 140 | 240 | 340 | 440 | 540 | 640 | |
050 | 150 | 250 | 350 | 450 | 550 | 650 | |
060 | 160 | 260 | 360 | 460 | 560 | 660 | |
070 | 170 | 270 | 370 | 470 | 570 | 670 | |
080 | 180 | 280 | 380 | 480 | 580 | 680 | |
090 | 190 | 290 | 390 | 490 | 590 | 690 |
Consider the following program, named err.cpp, that contains errors:
#include <stdio.h> void main() { int i; float i; i = 383; x = 13143.0; printf( "Integer value is %d\n", i ); printf( "Floating-point value is %f\n", x ); }
If we compile the above program, the following messages appear on the screen:
File: err.cpp (6,12): Error! E042: symbol 'i' already defined 'i' declared at: (5,9) (9,5): Error! E029: symbol 'x' has not been declared err.cpp: 12 lines, included 174, no warnings, 2 errors
The diagnostic messages consist of the following information:
In the above example, the first error occurred on line 6 of the file err.cpp. Error number 042 (with the appropriate substitutions) was diagnosed. The second error occurred on line 9 of the file err.cpp. Error number 029 (with the appropriate substitutions) was diagnosed.
The following sections contain a complete list of the messages. Runtime messages (messages displayed during execution) don't have message numbers associated with them.
A number of messages contain a reference to the ARM. This is the Annotated C++ Reference Manual, written by Margaret A. Ellis and Bjarne Stroustrup, and published by Addison-Wesley (ISBN 0-201-51459-1).
if( var = 0 )
You probably want to use ==, to test for equality.
int a = 12345678901234567890;
int foo( int a ) { int b = a + a; }
The message is issued at the end of the function.
struct Base { ~Base(); }; struct Derived : Base { virtual ~Derived(); };
It's usually considered good programming practice to declare virtual destructors in all classes used as base classes of classes having virtual destructors.
For example:
extern int __far *foo(); int __far *p_far = foo(); int __near *p_near = p_far; // truncated
Suppose we have the declaration char buffer[80]. Then the expression (&buffer + 3) is evaluated as (buffer + 3 * sizeof(buffer)), which is (buffer + 3 * 80), and not (buffer + 3 * 1), which is what most people expect to happen.
The ``address of'' operator (&) isn't required for getting the address of an array.
For example:
int *foo() { int k = 123; return &k; // k is an automatic variable }
For example:
class Private { int a; Private(); ~Private(); Private( const Private& ); };
In the following example, the statement following the return statement can't be reached:
void foo( int *p ) { *p = 4; return; *p = 6; }
In some cases, there may be a valid reason for retaining the variable. You can prevent the message from being issued through use of #pragma off(unreferenced), or adding a statement that assigns the variable to itself.
int foo( int a, int b ) { un_refed: return a + b; }
int foo( int a, int b ) { break; // illegal return a+b; }
int foo( int a, int b ) { case 4: // illegal return a+b; }
int foo( int a, int b ) { continue; // illegal return a+b; }
int foo( int a, int b ) { default: // illegal return a+b; }
int a; #else int c; #elif IN_IF int b; #endif
The #else, #elif, and #endif statements above are all illegal because there's no #if that corresponds to them.
int a; #else int c; #elif IN_IF int b; #endif
The #else, #elif, and #endif statements above are all illegal because there's no #if that corresponds to them.
int a; #else int c; #elif IN_IF int b; #endif
The #else, #elif, and #endif statements above are all illegal because there's no #if that corresponds to them.
int translate( int a ) { switch( a ) { case 1: a = 8; break; default: a = 9; break; default: // illegal a = 10; break; } return a; }
int a = b; // b has not been declared
int a; int b = a( 12 );
For example, both statements in the function below are invalid, since lvalues are expected where the additions are shown:
void foo( int a ) { ( a + 1 ) = 7; int b = ++ ( a + 6 ); }
void bar( int *p ) { label: *p = 0; label: return; }
void bar( int *p ) { *p = 0; goto label; // not defined }
The label referenced in the goto isn't defined.
int array[0]; // not allowed
int array[-1]; // not allowed
int array[ ][ ]; // not allowed
auto void foo() // invalid { }
int a; int b = *a;
char c; char *p1 = & & c; // not allowed char *p2 = & (c+1); // not allowed
struct S { int a; }; int &fun(); int a = fun().a;
struct S { int a; }; int *fun(); int a = fun()->a;
char a = 2; char a = 2; // not allowed
static int fun( void ); int k = fun(); // fun not defined by end of program
int fun( void ) { goto; }
int fun( int a ) { switch( a ) { case 1: return 7; case 2: return 9; case 1: // duplicate not allowed return 7; } return 79; }
struct S { unsigned bitfield :48; // too wide };
struct S { int bitfield :10; int :0; // ok, aligns to int int h :0; // err, field is named };
struct S { unsigned bitfield :-10; // can't be negative };
struct S { float bitfield : 10; // must be integral };
int array[10]; int i1 = array[0]; // ok int i2 = 0[array]; // same as above int i3 = 0[1]; // illegal
#i_goofed // not valid
#include // no header file #include stdio.h
Both examples are illegal.
#define mac(a,b) a+b int i = mac(123); // needs 2 parameters
void fun() { return 14; //not expecting return value }
struct S { int bits :6; int bitfield :10; }; S var; void* p = &var.bitfield; // illegal
#define mac(a,b) a+b int i = mac(1,2,3); // needs 2 parameters
extern int __based( __segname( "myseg" )) *pi; void bad() { try { throw pi; } catch( int __far16 *p16 ) { *p16 = 87; } }
Both the throw expression and catch statements cause this error to be diagnosed.
class C { public: C(); } // needs ";" int foo() { return 7; }
char c = '12345';
extern int foo( char* ); int bar() { register char c = 'c'; return foo( &c ); }
char *a = "no_ending_quote;
int foo( int a, float b, int *p ) { switch( a ) { case 1.3: // must be integral return p[b]; // index not integer case 2: b <<= 2; // can only shift integers default: return b; } }
class C { public: int c; }; C cv; int i = cv / 2;
extern int bar( int ); void foo( int a ) { if( a ) goto ending; bar( a ); ending: // needs statement following }
int foo( int a ) { switch( a ) { default: return 7; case 1: // needs statement following } return 18; }
int foo( int a ) { switch( a ) { case 7: return 7; default: // needs statement following } return 18; }
#if 1 int a; // needs #endif
#define bad_mac( a, b
#define mac( a, b) a+b int d = mac( 1, 2
#error my very own error message
typedef int TD(float); TD array[12];
typedef int ARR[10]; ARR fun( float );
typedef int TD(); TD fun( float );
struct S { char arr1[ 0xfffe ]; char arr2[ 0xfffe ]; char arr3[ 0xfffe ]; char arr4[ 0xfffffffe ]; };
#define CON 123 #define CON 124 // not same as previous
void fn() { extern int v = 1; }
struct S { S( S const &, int ); // S( S const & ); <-- declared by // compiler }; // ambiguity with compiler-generated copy // constructor // S( S const & ); S::S( S const &, int = 0 ) { }
#define badmac( a, b ) ## a ## b
float f = 123.9E+Q;
struct S { int a; int b :10; } v; int k = sizeof( v.b );
extern inline fun() { return 19; }
#include <stdarg.h> int foo( int a, int b ) { va_list args; va_start( args, a ); va_end( args ); return b; }
For the 16-bit Watcom C/C++ compilers:
For the 32-bit Watcom C/C++ compilers:
#define badmac( a, b, a ) a ## b
struct S1{ int f( int ); }; struct S2{ int f( int ); }; union un { S1 s1; S2 s2; virtual int vf( int ); };
union U { int a; int b; }; class S : public U { int s; };
class S { public: int s; }; union U : public S { int a; int b; };
class Undefined; class C : public Undefined { int c; };
In this example, Undefined only has a partial type, and therefore can't be used to determine storage layout.
class Dup { int d; }; class C : public Dup, public Dup { int c; };
extern "APL" void AplFunc( int* );
For example:
extern typedef int (*fn)( void );
static int;
short short x; short long y;
const const x; struct S { int virtual virtual fn(); };
typedef int TD; typedef float TD; // illegal
class C { }; class C { };
class C; int x = sizeof( C );
int foo( int a ) { switch( a ) { case 1: int b = 2; return b; default: // b bypassed return b + 5; } }
int foo( int a ) { switch( a ) { case 4 / 0: // illegal return a; } return a + 2; }
int foo( int a ) { switch( a ) { case 0x7FFF * 0x7FFF * 0x7FFF: // overflow return a; } return a + 2; }
struct S { virtual int wrong( void ) = 91; };
char *ptr; char __based( void ) __based( ptr ) *a;
enum Days { sun, mod, tues, wed, thur, fri, sat }; enum Days day = 2;
class C { public: extern unsigned bitf :10; };
class C { public: bitf :10; };
struct S { friend int bit1 :10; inline int bit2 :10; virtual int bit3 :10; };
All three declarations of bit-fields are illegal.
struct Base { int b; }; struct Derived : public public Base { int d; };
struct Base { int b; }; struct Derived : public protected Base { int d; };
struct S1 { int s; }; struct S2 { int s; }; struct Der : public S1, public S2 { void foo() { s = 2; }; // s is ambiguous };
struct Top { int t; }; struct Mid : public Top { int m; }; struct Bot : public Top, public Mid { void foo() { t = 2; }; // t is ambiguous };
struct Top { int t; }; class Bot : private Top { int foo() { return t; }; // t is private }; Bot b; int k = b.foo(); // foo is private
For example:
struct Top { int t; }; struct Mid : public Top { int m; }; class Bot : protected Mid { protected: // t can't be accessed int foo() { return t; }; }; Bot b; int k = b.foo(); // foo is protected
void fn() { char *p, *q; p += q; }
struct S { } x; void fn() { ++x; }
struct S { } x; void fn() { x = x + 1; }
struct S { } x; void fn() { x = 1 + x; }
int fn( char *p ) { return( 10 - p ); }
struct S { } x; void fn() { x = x * 1; }
struct S { } x; void fn() { x = 1 * x; }
struct S { } x; void fn() { x = x ^ 1; }
struct S { } x; void fn() { x = 1 ^ x; }
void fn( char *p ) { int a; a = p; }
struct Obj { char *p; ~Obj(); }; Obj far obj;
The last line causes this error to be displayed when the memory model is small (option ms), since the memory model for data is near.
struct Obj { char *p; int foo(); }; Obj far obj; int integer = obj.foo();
The last line causes this error to be displayed when the memory model is small (option ms), since the memory model for data is near.
struct Obj { char *p; }; void foo( Obj far *p ) { delete p; }
The second last line causes this error to be displayed when the memory model is small (option ms), since the memory model for data is near.
#include <stddef.h> int fn( void ) { return offsetof( double, sign ); }
class C1; class C2; void fun( C1* pc1, C2* pc2 ) { pc2 = pc1; }
int i, j; void fn() { ( i - 1 ) = j; 1 = j; }
union U { static int a; int b; int c; };
class C { auto int a; // can't specify auto };
int ************p; // transform this to ... typedef int ****PD1; typedef PD1 ****PD2; PD2 ****p;
float f = 1.2e78965;
float f = 1.2e-78965;
enum E { e1 = 0xFFFFFFFF, e2 = -1 };
auto int a;
const int a;
int foo( extern int a ) { return a; }
class C { C(); }; union U { int a; C c; // has constructor };
static int const con = 12; void foo() { con = 13; // error *(int*)&con = 13; // ok }
#include <stddef.h> struct S { unsigned b1 :10; unsigned b2 :15; unsigned b3 :11; }; int k = offsetof( S, b2 );
class C1; class C2; int foo( C1* ); int foo( C2* ); int k = foo( 5 );
char _based( void ) *pcb; char __far *pcf = pcb; // needs :> operator
Examples of typical uses are as follows:
extern int a; int *p = ( a > 7 ) ? &a : 12;
void *p; void *q = p + 2;
void *p; void *q = 2 + p;
void *p; void *q = ++p;
typedef int FT( int ); unsigned y = sizeof( FT );
void *p; unsigned size = sizeof( *p );
extern int goop(); int foo() { try { return goop(); } catch( struct S { int s; } ) { return 2; } }
enum E { e1, e2 }; void foo( short a ) { switch( a ) { case 1: case 0x10001: // converts to 1 as short break; } }
There are implicit scopes created for most control structures. Because of this, no code can access any of the names declared in the declaration. Although the code is legal, it might not be what you intended. For example:
void foo( int a ) { if( a ) int b = 14; }
There are implicit scopes created for most control structures. Because of this, no code can access any of the names declared in the declaration. Although the code is legal, it might not be what you intended. For example:
void foo( int a ) { if( a ) int c = 15; else int b = 14; }
void foo( int a ) { switch( a ) int b = 14; }
void *fn() { return this; }
void foo( int a ) { while( a ) int b = 14; }
void foo( int a ) { do int b = 14; while( a ); }
void fn( int **a ) { for( int i = 0; i < 10; ++i ) for( int j = 0; j < 10; ++j ) a[i][j] = i + j; }
The following example, however, illustrates a potentially erroneous situation:
void foo( int a ) { for( ; a<10; ) int b = 14; }
struct VBase { int v; }; struct Der : virtual public VBase { int d; }; extern VBase *pv; Der *pd = (Der *)pv;
extern int __far *p; void foo() { throw p; }
When the small memory model (ms option) is selected, the throw expression is diagnosed as erroneous. Similarly, only near pointers can be specified in catch statements when the data memory model is near.
class C { char *p; public: C(); ~C(); }; C& foo() { C auto_var; return auto_var; // not allowed }
void fn1( void ) // OK { } void fn2( void, void, void ) // Error! { }
#include <stddef.h> struct S { void *operator new( size_t, char ); }; void fn() { S *p = new ('a') S; }
char *p = "1234" L"5678";
#include <stddef.h> class C { public: static int stat; int memb; }; int size_1 = offsetof( C, stat ); // not allowed int size_2 = offsetof( C, memb ); // ok
void array[24];
int& array[24];
void& ref;
int & & ref;
char& *ptr;
struct S { S( int ); }; S *p = new S[10] ( 12 );
struct S { S(); int &ref; }; int& S::* p;
struct S { int s; }; extern int foo( S* ); extern int foo( S* const ); // not distinct enough
extern int foo( char ); extern int foo( short ); int k = foo( 4 );
#include <stdlib.h> struct Der { int s[2]; void* operator new( size_t, char ); void* operator new( size_t, short ); }; Der *p = new(10) Der;
int foo( int s ) { return s; } int foo( int s ) { return s; } // illegal
void fn( void *p ) { int a[10]; a = 0; a = p; a++; }
struct S { int operator int(); // can't have return type };
// operator char can only be a function int operator char = 9;
struct S { operator int( S& ); // can't have arguments };
struct S { void* ~S(); };
struct S { int ~S; // illegal };
struct S { ~S( S& ); };
struct S { int operator+; // illegal };
struct D B { int i; };
struct B { static int b; }; struct A : public B { }; int A::B::b = 2; // B not nested in A
The preceding example is illegal; the following is legal:
struct A { struct B { static int b; }; }; int A::B::b = 2; // B nested in A
struct D { int i; enum E { e1, e2, e3 }; }; enum E enum_var; // E not visible
struct A{ int a; }; int b; int c = B::A::b;
void fn() { int a; a = int( 1, 2 ); // Error! a = int( ( 1, 2 ) ); // OK }
For example:
typedef int TD( int, int a = 14 ); int (*p)( int, int a = 14 ) = 0;
void fn( int = 1, int, int = 3 );
Preventing overloaded operators from having default arguments enforces the property that binary operators will only be called from a use of a binary operator. Allowing default arguments would allow a binary operator + to function as a unary operator +. For example:
class C { public: C operator +( int a = 10 ); };
char* fun( const char* p ) { char* q; q = p; return q; }
static int foo( int a = 10 ); static int foo( int a = 10 ) { return a+a; }
void fn( int ); void fn( int, int = 1 );
Calling the function fn() with one argument is ambiguous, because it could match either the first fn() without any default arguments, or the second fn() with a default argument applied.
void fn( int, int = 1 ); void fn( int, char = 'a' );
Calling the function fn() with one argument is ambiguous, because it could match either the first fn() with a default argument, or the second fn() with a default argument applied.
void fn1( int , int ); void fn1( int , int = 3 ); void fn1( int = 2, int ); // OK void fn2( int , int ); void fn2( int = 2, int ); // Error!
enum { X, Y, Z }; // anonymous enum void fn() { enum *p; }
class C; void fun( C* p ) { p->~S(); }
struct S { void S::foo( void ) { } };
class C { public: int c; int goop(); }; int C::x = 1; C::not_decled() { }
void goop( int d ) { struct S { // can't access "d" int foo( int c, int b = d ) { return b + c; }; }; }
void goop( void ) { int a; struct S { // can't access "a" int foo( int c, int b = a ) { return b + c; }; }; }
Access declarations are used to increase access. A private access declaration is useless because there's no access level for which private is an increase in access. For example:
class Base { int pri; protected: int pro; public: int pub; }; class Derived : public Base { private: Base::pri; };
int foo(); int foo; struct S { int bad(); int bad; };
struct B { int f; }; struct C : B { int g; }; struct D : private C { protected: B::f; // adjust access };
In the above example, C is a direct base class of D, and B is a direct base class of C, but B isn't a direct base class of D.
class C { static int foo( int ); // private public: static int foo( float ); // public }; class B : private C { public: C::foo; };
class Base { public: int pub; protected: int pro; }; class Der : private Base { public: Base::pub; // ok public: Base::pro; // changes access };
class Base { public: int pub; protected: int pro; }; class Der : public Base { protected: Base::pub; // changes access protected: Base::pro; // ok };
struct S { struct T *link; };
In the above example, the class T is reported as not defined by the end of the class declaration. The code can be corrected in the following manner:
struct T; // declare T struct S { struct T *link; };
struct S { static operator int(); };
struct S { static ~S(); };
class C { public: static operator =( C&, int ); };
class C { public: int c; }; C& operator~( const C&, int );
class C { public: int c; }; C& operator += ( const C& );
class C { public: int c; }; C& operator+( const C&, int, float );
#include <stddef.h> struct S { void * operator new( size_t, char ); }; void fn() { S *p = new ('a') S; }
class C { public: int c; C* operator delete( void* ); C* operator delete [ ]( void* ); };
#include <stddef.h> class C { public: int c; C* operator new( size_t size ); C* operator new [ ]( size_t size ); };
void *operator new( int size ); void *operator new( double size, char c ); void *operator new [ ]( int size ); void *operator new [ ]( double size, char c );
class C; void operator delete( C* ); void operator delete [ ]( C* );
struct S { void operator delete( void *, char ); void operator delete [ ]( void *, char ); };
class C { public: long cv; }; C& operator ++( C&, unsigned );
struct S { int a; S *operator ->(); }; void fn( S &q ) { q->a = 1; // becomes (q.operator ->())->a = 1; }
class C { public: long cv; }; C& operator ++( unsigned, int );
int a[3] = { 1, 2, 3, 4 };
char ac[3] = "abc";
int b[3] = 3;
struct S { union { int S; // Error! char b; }; };
int e = { { 1 };
struct S { typedef int S; // Error! };
struct S { enum E { S, // Error! T }; };
A static member can't be declared with the same name as its containing class. For example:
struct S { static int S; // Error! };
class C { public: C& C( int ); };
class C { public: static C( int ); };
struct S { S( S const & ); // copy constructor };
class C { public: C( int ) const; C( float ) volatile; };
class C { public: virtual C( int ); };
void foo( int *p ) { p->int::~double(); }
struct S { S(int); operator int(); int a; }; int fn( int b, int i, S s ) { // i : s.operator int() // OR S(i) : s return b ? i : s; }
In the above example, i and s must be brought to a common type. Unfortunately, there are two common types, so the compiler can't decide which one it should choose, hence an ambiguity results.
class C { friend float; };
extern void foo(); friend void foo();
struct S; struct T { friend S; // should be "friend class S;" };
struct S { friend struct X { int f; }; };
class S; class T { friend class S; int tv; friend class S; };
extern void foo(); class T { friend void foo(); int tv; friend void foo(); };
typedef friend (*PF)( void );
struct S { int sv; }; S s; int foo() { int k; k = s; return k; }
struct S { S(int); S(char); }; S x = S(1.0);
struct S; int S::* p; // OK int S::a = 1; // Error!
union u { unsigned bit1 :10; unsigned :6; };
struct T { }; void fn() { T y = (T) 0; }
struct S { S(int); S(char); }; void fn() { S x = (S) 1.0; }
struct { int a; int b; };
static union { int a; int b; };
struct S { static union { int iv; unsigned us; }; };
static union { int iv; protected: unsigned sv; } u;
static union { int iv; private: unsigned sv; };
static union { int iv; void foo(); // error unsigned sv; };
static union { int iv; unsigned sv; typedef float F; F fv; };
static union { int iv; enum choice { good, bad, indifferent }; choice c; unsigned sv; };
int iv; unsigned sv; static union { int iv; unsigned sv; };
struct S { int sv1, sv2, sv3; }; struct T { ~T(); }; static union { S su; T tu; };
A union should only be used to organize memory in C++. Allowing union members to have assignment operators would mean that the same piece of memory could be assigned twice. For example:
struct S { int sv1, sv2, sv3; }; struct T { int tv; operator = ( int ); operator = ( float ); }; static union { S su; T tu; } u;
struct S { int sv1, sv2, sv3; }; static union { S su1; S su2; friend class S; };
template <class G> class S { G x; }; struct Q { struct S<int> { int x; }; }; void foo() { struct S<double> { double x; }; }
int foo() { struct local { static int s; }; local lv; lv.s = 3; return lv.s; }
struct S { S(int); S(char); }; S fn() { return 1.0; }
struct T { }; T fn() { return 0; }
void __based(__self) *fn( unsigned );
class S; S sv;
typedef int INT = 15;
struct S { struct N; // public private: struct N { // private }; };
extern int foo( int& ); extern int m; extern int n; int k = foo( m + n );
In the example, the value of m+n can't be converted to a reference. It could be converted to a constant reference, as shown in the following example:
extern int foo( const int& ); extern int m; extern int n; int k = foo( m + n );
struct S; struct T { T( S& ); }; struct S { operator T(); }; S s; extern int foo( T ); int k = foo( s ); // ambiguous
In the example, the argument s could be converted by both the constructor in class T and by the user-conversion in class S.
__segment s; void __based(s) *p; void __based(p) *q;
x; typedef int;
struct S { void foo() { static int nested_fun(); } };
__segment s; void fn( int __based(s) & x );
extern int foo( int, int ); int k = foo( 1, 2, 3 );
In the example, the function was declared to have two arguments. Three arguments were used in the call.
struct Priv { int p; }; struct Der : private Priv { int d; }; extern Der *pd; Priv *pp = (Priv*)pd;
struct Priv { int p; }; struct Der : private Priv { int d; }; Priv *foo( Der *p ) { return p; }
#include <stddef.h> ptrdiff_t diff( float *fp, int *ip ) { return fp - ip; }
In the example, a diagnostic results from the attempt to subtract a pointer to an int object from a pointer to a float object.
struct Priv { int p; }; struct Der : private Priv { int d; }; int foo( Der *pd, Priv *pp ) { return pd == pp; }
struct Prot { int p; }; struct Der : protected Prot { int d; }; extern Der *pd; Prot *pp = (Prot*)pd;
struct Prot { int p; }; struct Der : protected Prot { int d; }; Prot *foo( Der *p ) { return p; }
struct S; int near S::*mp;
struct Prot { int p; }; struct Der : protected Prot { int d; }; int foo( Der *pd, Prot *pp ) { return pd == pp; }
void goop( void ) { int a; struct S { int foo( int c, int b ) { return b + c + a; }; }; }
extern const int *pic; extern int *pi = pic;
extern unsigned j; unsigned i = ( j >= 0 ); // always 1 extern char *p; unsigned k = ( 0 <= p ); // always 1
extern unsigned j; unsigned i = ( j < 0 ); // always 0 extern char *p; unsigned k = ( 0 >= p ); // always 0
struct S { typedef int T; }; void fn( S *p ) { p->T = 1; }
virtual void foo(); struct S { int f; virtual void bar(); }; virtual void bar() { f = 9; }
struct S { int s1, s2; }; union S var;
union S { int s1, s2; }; struct S var;
int (*p)[ ];
void foo() { struct S { int bar(); }; }
extern void ext(); void foo() { class S { int s; public: friend void ext(); int q; }; }
struct ext { goop(); }; void foo() { class S { int s; public: friend class ext; int q; }; }
extern int a; extern int b; extern int c; int k = a > b > c;
void goop( int d ) { struct S { int foo( int c, int b ) { return b + c + d; }; }; }
#define TEST 143 int foo( int a, int b ) { if( TEST ) return a; return b; }
#define TEST 14-14 int foo( int a, int b ) { if( TEST ) return a; return b; }
#define TEST 0 int foo( int a, int b ) { switch ( TEST ) { case 0: return a; default: return b; } }
struct S { const int s; int i; };
struct S { int& r; int i; };
struct S { int m; static void fn() { m = 1; // Error! } };
struct S { operator int(); int a; }; double fn( S *p ) { return p->operator double(); }
struct S { static virtual int foo(); // error virtual int bar(); // ok static int stat(); // ok };
class C { protected: C( int ); public: int c; }; int cfun( C ); int i = cfun( 14 );
The last line is erroneous, since the constructor is protected.
class C { C( int ); public: int c; }; int cfun( C ); int i = cfun( 14 );
The last line is erroneous, since the constructor is private.
This problem is solved by requiring that a destructor be defined as virtual if polymorphic deletions must work. The delete expression will virtually call the correct destructor, which knows the correct size of the complete object.
This message informs you that the class you're deleting has virtual functions but it has a non-virtual destructor. This means that the delete won't work correctly in all circumstances. For example:
#include <stddef.h> struct B { int b; void operator delete( void *, size_t ); virtual void fn(); ~B(); }; struct D : B { int d; void operator delete( void *, size_t ); virtual void fn(); ~D(); }; void dfn( B *p ) { delete p; // could be a pointer to D! }
#include <stddef.h> struct S { int fun(); }; int s = offsetof( S, fun );
#include <stddef.h> struct S { enum SE { S1, S2, S3, S4 }; SE var; }; int s = offsetof( S, SE );
#include <stddef.h> struct S { int a; int b; int c[ offsetof( S, b ) ]; };
The exception to this rule in the C++ language involves restricted changes in the return type of virtual functions. The derived virtual function's return type can be derived from the return type of the base virtual function. For example:
struct B { virtual B *fn(); }; struct D : B { virtual D *fn(); };
int foo( char ); unsigned foo( char );
class C; extern C* pc1; C* pc2 = ++pc1; // C not defined int foo( C*p ) { return p->x; // C not defined }
extern int* i; void func() { *(i++); }
In the example, the expression is a reference to an integer that is meaningless in itself. The incrementation of the pointer in the expression is a side effect.
unsigned char c = 567;
extern unsigned s; unsigned char c = s;
class C { C( const C& ); public : int c; }; C cv;
int foo( int a, int b ) { if( a = b ) { return b; } return a; // always return 1 ? }
static int a = 9; int b = 89;
The variable a isn't referenced in the preceding example, and so, causes a warning to be generated. Following the warning, the informational message indicates the line at which a was declared.
int & ref;
int __suspect_name = 9;
int main(); int main( int );
void *p = new void;
typedef int tdfun( int ); tdfun *tdv = new tdfun;
typedef const int con_int; con_int* p = new con_int;
struct T { }; T x = 0;
struct S { S(int); S(char); }; S x = 1.0;
template <class T> class S; class X { friend class S; int f; friend class S; };
int *foo( const int *p ) { return p; }
int *bar( int * ); int *foo( const int *p ) { return bar( p ); }
template <class T> class { };
template <class T> T x[1];
template <class T> int foo( int * ); template <class T> T bar( int * );
// const is illegal typedef void (*baddcl)() const; struct S { void fun() const; int a; }; // "this" has type "S const *" void S::fun() const { this->a = 1; // Error! }
extern foo( struct S { int s; } );
template <class T> class C { T value; } fn( T x ) { C y; y.x = 0; return y; };
A common problem that results in this error is to forget to terminate a class or enum definition with a semicolon. For example:
struct S { int x,y; S( int, int ); } // missing semicolon ';' S::S( int x, int y ) : x(x), y(y) { }
struct S { static const int size = 1; };
struct S { void foo() = 0; };
struct S { void fn(); }; void cfn( const S *p ) { p->fn(); // Error! }
If fn() is declared as voice fn() const;, then the example above is valid.
template <class T> void f( T *p ) { } template <class T> void f( T *p ) { }
template <class T> void f2( T *p = 0 ) { }
typedef int T; int T( int ) // error! { } enum E { A, B, C }; void E() { enum E x = A; // use "enum E" } class C { }; void C() { class C x; // use "class C" }
int T( int ) { } typedef int T; // error! void E() { } enum E { A, B, C }; enum E x = A; // use "enum E" void C() { } class C { }; class C x; // use "class C"
struct S { void fn(); }; void cfn( volatile S *p ) { p->fn(); // Error! }
extern const int* pci; extern void *vp; int k = ( pci == vp );
extern const int* pci; extern volatile void *vp; int k = ( pci == vp );
void __far foo(); void __near *v = &foo;
int __far *ip; void __near *v = ip;
int a = 14; int b = sizeof( a++ );
In the example, the variable a still has a value of 14 after b has been initialized.
Furthermore, all references to the class or enum must be elaborated (that is, use class C instead of C) in order for subsequent references to be compiled properly.
struct X { X(X&); }; struct Y { X a[10]; }; Y yvar;
In the example, the variable yvar causes a default constructor for the class Y to be generated. The default constructor for Y attempts to call the default constructor for X in order to initialize the array a in class Y. The default constructor for X can't be defined because another constructor has been declared.
struct T { // should be class or function declaration friend int; };
int foo( char ); int foo( unsigned ); extern int (*p)( char ); int k = ( p == &foo ); // fails
The first foo can be passed as follows:
int foo( char ); int foo( unsigned ); extern int (*p)( char ); // introduce temporary static int (*temp)( char ) = &foo; // ok int k = ( p == temp );
int foo( char ); int foo( unsigned ); int ellip_fun( int, ... ); int k = ellip_fun( 14, &foo ); // fails
The first foo can be passed as follows:
int foo( char ); int foo( unsigned ); int ellip_fun( int, ... ); static int (*temp)( char ) = &foo; // introduce temporary int k = ellip_fun( 14, temp ); // ok
void fn( int a ) { delete a; // Error! }
void fn( const int &rc ) { int volatile &r = rc; // Error! }
void fn( volatile int &rv ) { int const &r = rv; // Error! }
void fn( const int &rc, volatile int &rv ) { int &r1 = rc; // Error! int &r2 = rv; // Error! }
struct S { int m(); static void fn() { m(); // Error! } };
The workaround for this problem is to recode the source so that the virtual functions make use of the va_list type found in the stdarg.h header file. For example:
#include <iostream.h> #include <stdarg.h> struct B { virtual void fun( char *, ... ); }; struct D : B { virtual void fun( char *, ... ); }; void B::fun( char *f, ... ) { va_list args; va_start( args, f ); while( *f ) { cout << va_arg( args, char ) << endl; ++f; } va_end( args ); } void D::fun( char *f, ... ) { va_list args; va_start( args, f ); while( *f ) { cout << va_arg( args, int ) << endl; ++f; } va_end( args ); }
The previous example can be changed to the following code with corresponding changes to the contents of the virtual functions:
#include <iostream.h> #include <stdarg.h> struct B { void fun( char *f, ... ) { va_list args; va_start( args, f ); _fun( f, args ); va_end( args ); } virtual void _fun( char *, va_list ); }; struct D : B { // this can be removed since using B::fun // results in the same behaviour // since _fun is a virtual function void fun( char *f, ... ) { va_list args; va_start( args, f ); _fun( f, args ); va_end( args ); } virtual void _fun( char *, va_list ); }; void B::_fun( char *f, va_list args ) { while( *f ) { cout << va_arg( args, char ) << endl; ++f; } } void D::_fun( char *f, va_list args ) { while( *f ) { cout << va_arg( args, int ) << endl; ++f; } } // no changes are required for users of the class B x; D y; void dump( B *p ) { p->fun( "1234", 'a', 'b', 'c', 'd' ); p->fun( "12", 'a', 'b' ); } void main() { dump( &x ); dump( &y ); }
struct Base {}; struct Derived : virtual Base {}; Derived __based( void ) *p_derived; Base __based( void ) *p_base = p_derived; // error
The conversion would be allowed if the base class weren't virtual.
The base class in the original member pointer isn't a unique base class of the derived class.
class C; int fun( C& x ) { return x.y; // class C not defined }
struct S; void fn( int S::* mp, int *p ) { if( p == mp ) p[0] = 1; }
struct S; void fn( int S::* mp, int *p ) { if( mp == p ) p[0] = 1; }
struct S; int S::* fn() { int a; return a; }
struct ambiguous{ }; struct base1 : public ambiguous { }; struct base2 : public ambiguous { }; struct derived : public base1, public base2 { }; foo( derived &object ) { throw object; }
The throw causes an error to be displayed because an object of type derived can't be converted to an object of type ambiguous.
struct S { int a; S( int x = 1 ) : a(x) { } };
This message warns you that an ambiguous construct has been resolved in a certain direction. In this case, the construct has been determined to be part of a type.
This message warns you that an ambiguous construct has been resolved in a certain direction. In this case, the construct has been determined to be part of an expression (a function-like cast).
This message warns you that an ambiguous construct couldn't be resolved by the compiler. Please report this to QNX Software Systems Limited so that the problem can be analysed.
This message warns you that another ambiguous construct was found inside an ambiguous construct. The compiler correctly disambiguates the construct.
struct S { virtual int foo(); }; static S sv; extern int bar( S, ... ); static int test = bar( sv, 14, 64 );
The call to bar() causes a warning, since the structure S contains information associated with the virtual function for that class.
This message warns you that an ambiguous construct has been used.
#pragma aux this_in_SI parm caller [si] [ax]; struct S { void __pragma("this_in_SI") foo( int ); void __pragma("this_in_SI") foo( char ); };
struct S1 { int a; }; struct S2 : S1 { int b; }; struct S3 : S2, S1 { int c; }; S1* fn( S3 *p ) { return p; }
In the example, class S1 occurs ambiguously for an object or pointer to an object of type S3. A pointer to an S3 object can't be converted to a pointer to an S1 object.
void f() { try { // code that may throw an exception } catch( int x ) { // handle 'int' exceptions } catch( ... ) { // handle all other exceptions } }
struct S { virtual int foo(); }; static S sv; extern "C" int bar( S ); static int test = bar( sv );
The call to bar() causes a warning, since the structure S contains information associated with the virtual function for that class.
For example:
struct BASE {}; struct DERIVED : public BASE {}; foo() { try { // code for try } catch( BASE b ) { // [1] // code } catch( DERIVED ) { // error: [1] // code } catch( BASE* pb ) { // [2] // code } catch( DERIVED* pd ) {// error: [2] // code } catch( void* pv ) { // [3] // code } catch( int* pi ) { // error: [3] // code } catch( BASE& br ) { // error: [1] // code } catch( float*& pfr ) {// error: [3] // code } }
Each erroneous catch specification indicates the preceding catch block that caused the error.
void fn( int, int = 1 ); void fn( int );
Calling the function fn() with one argument is ambiguous because it could match either the first fn() with a default argument applied, or the second fn() without any default arguments.
extern "C" void fn( void ); void fn( void ) { }
foo( int a ) { if(a) goto tr_lab; try { tr_lab: throw 1234; } catch( int ) { if(a) goto tr_lab; } if(a) goto tr_lab; }
All the preceding goto statements are illegal. The error is detected at the label for forward jumps and at the goto for backward jumps.
foo( int a ) { if(a)goto ca_lab; try { if(a)goto ca_lab; } catch( int ) { ca_lab: } if(a)goto ca_lab; }
All the preceding goto statements are illegal. The error is detected at the label for forward jumps and at the goto for backward jumps.
extern void goop(); void foo() { try { goop(); } // a catch block should follow! }
In the example, there were no catch blocks after the try block.
This message indicates that the indicated expression isn't meaningful. An expression is meaningful when a function is invoked, when an assignment or initialization is performed, or when the expression is cast to void. For example:
void foo( int i, int j ) { i + j; // not meaningful }
int k; void foo( int i, int j ) { i + j, // no side effect (note comma) k = 3; }
struct S { void fun(); }; virtual void S::fun() { }
class S; int foo( S*p ) { return p->x; }
The variable p is a pointer to an undefined class, and so causes an error to be generated. Following the error, the informational message indicates the line at which the class S was declared.
For more information about this pragma, see the ``TEMPLATE_DEPTH pragma'' in the following chapters:
For more information about this pragma, see the ``TEMPLATE_DEPTH pragma'' in the following chapters:
struct Partial { struct Nested : Partial { int n; }; };
int amb( char ); // ambiguous int amb( unsigned char ); // ambiguous int amb( char, char ); int k = amb( 14 );
The constant value 14 has an int type, and so the attempt to invoke the function amb is ambiguous. The first two functions are ambiguous (and will be displayed); the third isn't considered (nor displayed), since it's declared to have a different number of arguments.
struct S { S( int ); operator int(); S operator+( int ); }; S s(15); int k = s + 123; // "+" is ambiguous
In the example, the + operation is ambiguous because it can be implemented by the addition of two integers (with S::operator int applied to the second operand) or by a call to S::operator+. This informational message indicates that the first is possible.
#undef __cplusplus #undef __DATE__ #undef __FILE__ #undef __LINE__ #undef __STDC__ #undef __TIME__
None of the preceding directives is permitted.
#define __cplusplus 1 #define __DATE__ 2 #define __FILE__ 3 #define __LINE__ 4 #define __STDC__ 5 #define __TIME__ 6
None of the preceding directives is permitted.
template <class T> void foo( T, T * ) { } void bar() { foo(1); // could not instantiate }
The function template for foo() can't be instantiated for a single argument, causing an error to be generated. Following the error, the informational message indicates the line at which foo() was declared.
int Fun(); int j = ++Fun; // illegal
In the example, the attempt to increment a function is illegal.
extern int Fun(); void foo() { Fun = 0; // illegal }
In the example, the attempt to assign zero to a function is illegal.
extern int Fun(); void foo() { void* p = 3[Fun]; // illegal }
In the example, the attempt to subscript a function is illegal.
struct S { ~S(); }; S::~S() { }
struct S { ~S(); }; struct T : S { ~T() {} }; S::~S() { }
int ovload( char ); int ovload( float ); int routine( int (*)( int ); int k = routine( ovload );
The first argument for the function routine can't be converted, resulting in the informational message.
main( int argc, char* argv ) { if( (void)argc ) { return 5; } else { return 9; } }
Conditional expressions, such as the one illustrated in the if statement can't have a void type.
struct S { int bits :6; int bitfield :10; }; S var; int& ref = var.bitfield; // illegal
class X; // declared, but not defined extern X& foo(); // returns reference (ok) extern X obj; void goop() { obj = foo(); // error }
class C { C(); }; int foo() { return 0 == &C::C; }
class C { ~C(); }; int foo() { return 0 == &C::~C; }
struct C { C( C& ); C( int ); }; C & c1 = 1; C c2 = 2;
The initializations of c1 and c2 are erroneous, since temporaries are being bound to non-const references:
struct S; S * fn( S &y ) { // assuming no operator '&' defined return &y; }
void fn( ... ) { }
#include <stdarg.h> void fn( int &r, ... ) { va_list args; // address of 'r' is address of // object 'r' references so // 'va_start' won't work properly va_start( args, r ); va_end( args ); }
#include <stdarg.h> struct S { S(); }; void fn( S c, ... ) { va_list args; // Watcom C++ passes a pointer to // the temporary created for passing // 'c' rather than pushing 'c' on the // stack so 'va_start' won't work // properly va_start( args, c ); va_end( args ); }
#pragma aux never_returns aborts; void fn( int, int ); void __pragma("never_returns") fn( int, int );
int (* __pascal ok)(); int (* __pascal not_ok);
struct A { void virtual fn( int ) = 0; }; A x;
struct A { void virtual fn( int ) = 0; }; struct D : A { }; D x;
struct A { void virtual fn( int ) = 0; }; struct D : A { }; D x;
extern int (*pfn)( int, int ); int k = pfn( 1, 2, 3 );
In the example, the function pointer was declared to have two arguments. Three arguments were used in the call.
int i = 0123456789; // invalid octal constant double d = 0123456789; // missing '.'?
template <class T> struct S { void f1() { // error missing '}' }; template <class T> struct X { void f2() { } };
struct S { S( int x ) : a(x), b(x // missing parenthesis { } };
struct S { char a[ ]; int b; };
struct B { int b; char a[ ]; }; struct D : B { int d; };
struct B { int b; }; struct D : B { int d; char a[ ]; };
class Abstract { public: virtual int foo() = 0; }; class Derived : Abstract { public: int foo(); }; int xyz; void func( void ) { try { throw Derived(); } catch( Abstract abstract ) { // object xyz = 1; } }The catch clause in the preceding example would be diagnosed as improper, since an abstract class is specified. The example could be coded as follows:
class Abstract { public: virtual int foo() = 0; }; class Derived : Abstract { public: int foo(); }; int xyz; void func( void ) { try { throw Derived(); } catch( Abstract & abstract ) { // reference xyz = 1; } }
struct S { int foo(); int bar(); int fun(); }; int S::fun( int i ) { return (i ? foo : bar)(); }
Neither foo nor bar can be specified as shown in the example. The example can be properly coded as follows:
struct S { int foo(); int bar(); int fun(); }; int S::fun( int i ) { return i ? foo() : bar(); }
struct Base {}; struct Derived : Base {}; Base b; Derived* ReturnPtr() { return &b; } Derived& ReturnRef() { return b; }
The following program would be acceptable:
struct Base {}; struct Derived : Base {}; Base b; Derived* ReturnPtr() { return (Derived*)&b; } Derived& ReturnRef() { return (Derived&)b; }
template <class T> struct S { typedef int X; static X fn( int ); static X qq; }; template <class T> S<T>::X fn( int ) {// should be 'S<T>::fn' return fn( 2 ); } template <class T> S<T>::X qq = 1; // should be 'S<T>::q' S<int> x;
struct abstract_class { abstract_class( int ); virtual int foo() = 0; }; void goop() { throw abstract_class( 17 ); }
The throw expression is illegal, since it specifies an abstract class.
typedef int __far FARINT; FARINT __far *p; // repeated __far modifier
struct S { int x,y; S( int, int ); } // missing semicolon ';' S::S( int x, int y ) : x(x), y(y) { }
class S; S foo(); int goo() { foo(); }
In the example, foo() can't be invoked because the class that it returns hasn't been defined.
class S { public: int arr[3]; S(); }; S::S() : arr( 1, 2, 3 ) {}
In the example, arr can't be specified as a constructor initializer. Instead, the array may be initialized within the body of the constructor:
class S { public: int arr[3]; S(); }; S::S() { arr[0] = 1; arr[1] = 2; arr[2] = 3; }
#include __FILE__
struct B { }; struct D : virtual B { }; struct X { virtual B *fn( int, ... ); }; struct Y : X { virtual D *fn( int, ... ); };
struct Obj { char *p; Obj(); }; Obj far obj;
The last line causes this error to be displayed when the memory model is small (switch ms), since the memory model for data is near.
A conflict between class modifiers for classes related through inheritance has been detected:
The conflict can be resolved by ensuring that all classes related through inheritance have the same class modifiers. For example:
struct __cdecl B1 { virtual void fn( int ); }; struct __pascal B2 { virtual void fn( int ); }; struct D : B1, B2 { virtual void fn( int ); };