22

Considering the following piece of code:

#include <iostream>

auto main() -> int {
  double x(7.0);
  int i{x};
  std::cout << "i = " << x << std::endl;

  return 0;
}

  • When compiled in GCC4.9 it compiles fine with only a warning:

    warning: narrowing conversion of ‘x’ from ‘double’ to ‘int’ inside { }


  • Compiling with either Clang3.3 or VC++2013 gives a compile error:

    error: type 'double' cannot be narrowed to 'int' in initializer list error C2397: conversion from 'double' to 'int' requires a narrowing


Questions:

  • Which of the compilers is right according to the standard?

  • Is there any reason why the compilers mentioned above should exhibit such diverse behaviour?

Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
101010
  • 41,839
  • 11
  • 94
  • 168
  • Note that GCC user to emit an error for this code (I don't remember when exactly this behaviour changed.) – juanchopanza Jun 04 '14 at 08:31
  • 5
    GCC 4.6 gives an error, it was downgraded to a "pedwarn" for GCC 4.7 for [PR 49793](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49793) so now it's a warning, enabled by default, and can be made into an error with `-pedantic-errors` or `-Werror=narrowing` – Jonathan Wakely Jun 04 '14 at 09:11

1 Answers1

19

The answer

Both compilers are correct!


Explanation

The Standard doesn't distinguish between an error and a warning, both go under the category of Diagnostics.

1.3.6 diagnostic message [defns.diagnostic]

message belonging to an implementation-defined subset of the implementation's output messages

Since the Standard says that a diagnostic is required in case a program is ill-formed, such as when a narrowing-conversion takes place inside a braced-initializer, both compilers are confirming.

Even if the program is ill-formed from the Standards point of view, it doesn't mandate that a compiler halts compilation because of that; an implementation is free to do whatever it wants, as long as it issues a diagnostic.



The reason for gcc's behavior?

Helpful information was provided by @Jonathan Wakely through comments on this post, below are a merge of the two comments;

he exact reason is that GCC made it an error at one point and it broke ALL THE PROGRAMS so it got turned into a warning instead. Several people who turned on the -std=c++0x option for large C++03 codebases found harmless narrowing conversions to cause most of the porting work to go to C++11

See e.g. PR 50810 where Alisdair reports narrowing errors were >95% of the problems in Bloomberg's code base.

In that same PR you can see that unfortunately it wasn't a case of "let's just issue a warning and be done with it" because it took a lot of fiddling to get the right behaviour.

Community
  • 1
  • 1
Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
  • 16
    +1 The exact reason is that GCC made it an error at one point and it broke **ALL THE PROGRAMS** so it got turned into a warning instead. Several people who turned on the `-std=c++0x` option for large C++03 codebases found harmless narrowing conversions to cause most of the porting work to go to C++11, e.g. `for (int i=0; i<10; ++i) char c[] = { 'f', 'o', 'o', '0' + i , '\0' };` where the value never goes out of range, but is technically a narrowing conversion – Jonathan Wakely Jun 04 '14 at 09:00
  • I thought one had to be wrong! - Sweet answer, and I really like the quote from imaginary guy! – Matt Coubrough Jun 04 '14 at 09:13
  • 2
    See e.g. [PR 50810](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50810) where Alisdair reports narrowing errors were >95% of the problems in Bloomberg's code base (and in that same PR you can see that unfortunately it wasn't a case of _"let's just issue a warning and be done with it"_ because it took a lot of fiddling to get the right behaviour) – Jonathan Wakely Jun 04 '14 at 09:22