Question

I've done some heavy refactoring of some C++ code, and discovered numerous bugs arising from implicit conversions that I'm not aware of.

Example

struct A *a();

bool b() {
    return a();
}

void c() {
    int64_t const d(b());
}

Issues

  1. In b, the return type of a is silently cast to bool.
  2. In c, the value returned from b is silently promoted to int64_t.

Question

How can I receive warnings or errors for the implicit conversion between primitive types?

Note

  1. The use of -Wconversion seems to only pick up several arbitrary conversions unrelated to the example above.
  2. BOOST_STRONG_TYPEDEF is not an option (my types need to be PODs, as they're used in disk structures).
  3. C is also of interest, however this problem pertains to a C++ code base.
Was it helpful?

Solution

In the C++ programming language, 3rd edition, appendix C.6, namely "Implicit Type Conversion", Bjarne Stroustrup classifies conversions as promotions and conversions: the first ones "preserve values" (that's your case 2), the second ones doesn't (case 1).

About conversions, he says that "The fundamental types can be converted into each other in a bewildering number of ways. In my opinion, too many conversions are allowed." and "A compiler can warn about many questionable conversions. Fortunately, many compilers actually do."

promotions on the other side are safe, and it seems like a compiler is not supposed to give a warning for them.

Compiler warnings are usually not mandatory. Usually in the C++ drafts and final ANSI documents it is reported that "implementers should issue a warning" where suggested: you can check it yourself for further information if needed.

EDITED: added C++11 note:

In The C++ programming language, 4th edition, the appendix of the 3rd edition has been reported and extended as section 10.5, "Implicit Type Conversion" again.

Being the previous considerations the same, C++11 more precisely define "narrowing conversions" and adds up the {}-initializer notation (6.3.5), with which truncations lead to a compilation error.

OTHER TIPS

If you are using gcc have you tried -Wall -Wextra basically check this page
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

If it is not GCC please post the compiler details.

Microsoft Visual C++ would give a warning about the narrowing conversion from A* to bool.

See Compiler Warning C4800

Promotion on the other hand is not a "dangerous" conversion, because it's impossible to lose data.

EDIT: Demonstration

C:\Users\Ben>copy con test.cpp
bool f( void ) { return new int(); }
^Z
        1 file(s) copied.

C:\Users\Ben>cl /c /W4 test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
test.cpp(1) : warning C4800: 'int *' : forcing value to bool 'true' or 'false' (
performance warning)

As far as I understand, you cannot control implicit conversion between primitive types: it's mandated by the standard and any compliant compiler will just perform it silently.

Are you sure an approach like BOOST_STRONG_TYPEDEF won't work in your problem? A class with no virtual member functions and just one primitive data member is basically nothing more than a POD data type. You can just follow the same approach and only allow conversion to the base primitive type; example:

#include <iostream>
#include <stdexcept>

struct controlled_int {
  // allow creation from int
  controlled_int(int x) : value_(x) { };
  controlled_int& operator=(int x) { value_ = x; return *this; };
  // disallow assignment from bool; you might want to use BOOST_STATIC_ASSERT instead
  controlled_int& operator=(bool b) { throw std::logic_error("Invalid assignment of bool to controlled_int"); return *this; };

  // creation from bool shouldn't happen silently
  explicit controlled_int(bool b) : value_(b) { };

  // conversion to int is allowed
  operator int() { return value_; };

  // conversion to bool errors out; you might want to use BOOST_STATIC_ASSERT instead

  operator bool() { throw std::logic_error("Invalid conversion of controlled_int to bool"); };

  private:
    int value_;
};

int main()
{
  controlled_int a(42);

  // This errors out:
  // bool b = a;

  // This gives an error as well:
  //a = true;

  std::cout << "Size of controlled_int: " << sizeof(a) << std::endl;
  std::cout << "Size of int: " << sizeof(int) << std::endl;

  return 0;
}

You can use one of the available static analysis tools, programs like clint or C++ equivalents, or one of the commercially available tools. Many of these tools can pick out problematic implicit conversions.

Write a custom clang plugin to diagnose your problems. We do a lot of this in the LibreOffice code. Come browse our source if you want inspiration at http://cgit.freedesktop.org/libreoffice/core/tree/compilerplugins/clang

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top