This page documents longer explanations for diagnostics in C/C++ front-ends. Please, feel free to suggest new content in gcc-help mailing list.

TODO

%D may be used uninitialized [-Wuninitialized]

[ Permalink ]

A variable that has not been initialized is read at some point in the code. Reading a uninitialized variable leads to undefined behaviour. Whether a variable is assigned a value before reading it cannot be decided in general. Depending on the optimization level, the version of GCC and the particular code, GCC may not be able to detect that a variable is actually always initialized and give a false warning. On the other hand, it may be able to detect that the variable is never used apart from uninitialized use and not warn.

See also -Wuninitialized in GCC manual

warning: passing argument %d of %D from incompatible pointer type; note: expected ‘const char **’ but argument is of type ‘char **’

[ Permalink ]

See the C++ FAQ Lite (this question applies to both C and C++):

http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17

C++ FE

error: uninitialized const 'd' [-fpermissive], note: 'const class D' has no user-provided default constructor

[ Permalink ]

   1    class C { };
   2    class D : public C { };
   3    const D d;

As mandated by the C++ standard (8.5 [decl.init], para 9 in C++03, para 6 in C++0x), G++ does not allows objects of const-qualified type to be default initialized unless the type has a user-declared default constructor. Code that fails to compile can be fixed by providing an initializer e.g.

   1     const D d = D();

error: there are no arguments to 'f' that depend on a template parameter, so a declaration of 'f' must be available

[ Permalink ]

   1     template<typename T>
   2     struct base
   3     {
   4       void f();
   5     };
   6     template<typename T>
   7     struct derived : public base<T>
   8     {
   9       void g() { f(); }
  10     };

The C++ standard says (14.6.2 [temp.dep] para 3) that lookup of unqualified names (such as f in the example) does not look in a "dependent base", i.e. a base class which depends on a template parameter. To tell the compiler that f is a member and lookup should include dependent bases, it must be qualified as either this->f() or base<T>::f(). See Name lookup, templates, and accessing members of base classes or the C++ templates FAQ or C++ FAQ Lite for further details.

undefined reference to `S::a'

[ Permalink ]

Some people are surprised to get a linker error when using static const members in conditional expressions (i.e. the ?: operator) like so:

   1 struct S
   2 {
   3     static const int a = 1;
   4     static const int b = 2;
   5 };
   6 int main(int argc, char** argv)
   7 {
   8    return argc > 1 ? S::a : S::b;
   9 }

This program is invalid and will fail to link:

/tmp/ccATW9fH.o: In function `main':
n.cc:8: undefined reference to `S::a'
n.cc:8: undefined reference to `S::b'
collect2: error: ld returned 1 exit status

The C++ standard says ([basic.def.odr] 3.2 paragraph 2) "A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied." and (paragraph 3) "Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required."

In the example above the lvalue-to-rvalue conversion cannot be applied, because (x?a:b) is an lvalue when a and b are both lvalues of the same type.

The same link error can happen if the static const member is used as an argument to a function which has reference parameters e.g.

   1 #include <algorithm>
   2 struct S
   3 {
   4     static const int a = 1;
   5     static const int b = 2;
   6 };
   7 int main(int argc, char** argv)
   8 {
   9    return std::max(S::a, S::b);
  10 }

It should be noted that with optimization enabled the variables may not be referenced, due to inlining or constant propagation, and so linking might succeed, but the program is still technically invalid.

The program can be fixed by providing a definition of the variables and/or by forcing either variable to be converted to an rvalue:

   1 struct S
   2 {
   3     static const int a = 1;
   4     static const int b = 2;
   5 };
   6 const int S::a;  // definition
   7 const int S::b;  // definition
   8 int main(int argc, char** argv)
   9 {
  10    return argc > 1 ? S::a : (int)S::b;
  11 }

See also Declare and Define Static Members and How do I define an in-class constant?

N.B. In February 2012 DR 712 updated the language so that the static variables in the conditional expressions above are no longer odr-used, so definitions are no longer required in the conditional expression case. Definitions are still required for cases like the std::max() example. That DR is not implemented by any version of G++ (at the time of writing GCC 4.7.1 is the latest release.)

undefined reference to vtable for X

[ Permalink ]

Every polymorphic class requires a virtual table or vtable describing the type and its virtual functions. Whenever possible the vtable will only be generated and output in a single object file rather than generating the vtable in every object file which refers to the class (which might be hundreds of objects that include a header but don't actually use the class.) The cross-platform C++ ABI states that the vtable will be output in the object file that contains the definition of the key function, which is defined as the first non-inline, virtual function declared in the class. If you do not provide a definition for the key function (or fail to link to the file providing the definition) then the linker will not be able to find the class' vtable.

In this example, X::i() is the key function because X::f() is not virtual and X::g() and X::h() are inline (and the key function is never a destructor):

   1 class X {
   2   virtual ~X();
   3   void f();
   4   virtual void g() { }
   5   virtual void h();
   6   virtual void i();
   7   virtual void j();
   8 };
   9 inline void X::h() { }

To fix the linker error be sure you have provided a definition for the first non-inline virtual function declared in the class. It may be possible to improve the error message, although this is far from trivial.

warning: deleting object of polymorphic class type 'Base' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]

[ Permalink ]

Deleting an object through a pointer to its base class will only run the derived class destructor if the base class destructor is virtual. If the destructor of the base class is not virtual then the delete operation has undefined behaviour, often resulting in (but not limited to) leaking memory and other resources managed by the derived class.

G++ will warn when delete is used with a polymorphic type (i.e. a type that has virtual functions) that does not have a virtual destructor e.g.

   1 class Base {
   2 public:
   3   virtual void foo() = 0;
   4 };
   5 
   6 class Derived : public Base {
   7 public:
   8   virtual void foo() {}
   9   ~Derived()         {}
  10 };
  11 
  12 void bar(Base* p)
  13 {
  14   p->foo();
  15   delete p;  // warning!
  16 }
  17 
  18 void baz(Derived* p)
  19 {
  20   p->foo();
  21   delete p;  // warning!
  22 }
  23 
  24 int main() {
  25   Derived* d1 = new Derived();
  26   bar(d1);
  27   Derived* d2 = new Derived();
  28   baz(d2);
  29 }

This code produces two warnings:

d.C: In function 'void bar(Base*)':
d.C:15:10: warning: deleting object of abstract class type 'Base' which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor]
   delete p;  // warning!
          ^
d.C: In function 'void baz(Derived*)':
d.C:21:10: warning: deleting object of polymorphic class type 'Derived' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]
   delete p;  // warning!
          ^

The first warning says bar will cause undefined behaviour, because Base is an abstract class so the actual object being deleted must be some type derived from Base (because an abstract class can only be used as a base class of another type) and because there is no virtual destructor the derived class destructor will not be called, resulting in undefined behaviour.

The second warning says baz might cause undefined behaviour, because the delete operation is safe if the object being destroyed is a Derived, but unsafe if it is some type derived from Derived. In the code above the call to baz is actually safe, but G++ still issues a warning for baz because a class that has virtual functions suggests it is likely (or at least possible) it will be used as a base class, in which case the delete operation would be unsafe e.g.

   1 // Base, Derived and baz() defined as above
   2 
   3 class MoreDerived : public Derived {
   4   std::string str;
   5 public:
   6   virtual void foo() { }
   7   ~MoreDerived() { }
   8 };
   9 
  10 int main() {
  11   MoreDerived* md = new MoreDerived();
  12   baz(md);
  13 }

In this example the MoreDerived destructor will not execute, causing a memory leak.

The  will cause undefined behaviour warning always indicates a real bug that should be fixed, either by adding a virtual destructor, or by deleting the correct type instead of the base class.

The  might cause undefined behaviour warning indicates a potential bug, but the warning will sometimes be issued for correct code, as in the first example above. Adding a virtual destructor will ensure the code is safe and so prevents the warning. Alternatively, the warning will not be issued if the compiler knows the class cannot be derived from i.e. if the class uses the C++11 final specifier

   1 class Derived final : public Base {
   2   // ...
   3 };

In C++98 and C++03 code the alternative spelling __final can be used instead (this is a GCC extension.)

(The -Wdelete-non-virtual-dtor warning and final specifier are supported by GCC 4.7.0 and later releases.)

None: VerboseDiagnostics (last edited 2013-04-04 16:11:35 by 81)