title: Do unsigned integers get promoted to signed? What is the type of expression (uint16_t)-1 * (uint16_t)-1
body: <p>For <code>uint32_t</code> and <code>uint64_t</code> results are expected, but promotions for <code>uint8_t</code> and <code>uint16_t</code> are strange. Tests on c++14/c++17, gcc and clang, 64-bit linux, <code>sizeof(int) == 4</code>.</p>
  <pre><code>#include &lt;cstdint&gt;    
  using namespace std;
  
  static_assert( uint8_t(-1)*uint8_t(-1) == 0xfe01);  // OK, but why not 1?
  static_assert( uint8_t(-1)*uint8_t(-1) == 1);       // error: static assertion failed
  static_assert( uint16_t(-1)*uint16_t(-1) == 1);     // error: static_assert expression is not an integral constant expression
  static_assert( uint32_t(-1)*uint32_t(-1) == 1);     // OK
  static_assert( uint64_t(-1)*uint64_t(-1) == 1);     // OK
  </code></pre>
  <p>Is in the following case <code>std::uint16_t</code> promoted to int?</p>
  <pre><code>static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));
  </code></pre>
  <p>The compiler messages are:</p>
  <pre><code>error: static_assert expression is not an integral constant expression
  static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));
  
  note: value 4294836225 is outside the range of representable values of type 'int'
  static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));
  </code></pre>
  <p>More interestingly the same assert for <code>std::uint8_t</code> is correct, but <em>fails</em>:</p>
  <pre><code>static_assert( uint8_t(-1)*uint8_t(-1) == uint8_t(uint8_t(-1)*uint8_t(-1)));  //error: static_assert failed
  static_assert( uint8_t(-1)*uint8_t(-1) == 0xfe01);  // does not fail
  </code></pre>
  <p>So it looks like <code>uint8_t</code> is promoted to <code>uint16_t</code>, but <code>uint16_t</code> is promoted to <em>signed</em> <code>int</code>. <code>uint32_t</code> is not promoted <code>uint64_t</code>.</p>
  <p>Anyone can tell me why these promotions are done, is it specified in standard, or can differ on different implementations?</p>