Date: Sat, 26 Oct 2013 14:09:12 -0400
Consider:
int
stest()
{
return -1 << 0;
}
With clang++ using -O3, the assembly is:
__Z5stestv: ## @_Z5stestv
.cfi_startproc
## BB#0: ## %entry
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
movl $-1, %eax
popq %rbp
ret
.cfi_endproc
Which looks pretty good to me (just returns -1).
But:
constexpr
int
stest()
{
return -1 << 0;
}
Yields:
test.cpp:103:1: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
stest()
^
test.cpp:105:15: note: left shift of negative value -1
return -1 << 0;
^
1 error generated.
What danger, or what non-portable behavior has been prevented here?
Might we reword [expr.shift]/p2 in terms of shifting 1 bits off of the most significant end, instead of in terms of E1*2^E2?
The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. <del>If E1 has an unsigned type, the value of the result is E1 × 2^E2, reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1 × 2^E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise<del><ins>If E1 has signed type and the result would have fewer non-zero bits than E1</ins>, the behavior is undefined.
Indeed, the conflation of bit shifts with multiplying / dividing by 2 has been a never-ending source of bugs over the decades. Let's just say no to that.
Howard
int
stest()
{
return -1 << 0;
}
With clang++ using -O3, the assembly is:
__Z5stestv: ## @_Z5stestv
.cfi_startproc
## BB#0: ## %entry
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
movl $-1, %eax
popq %rbp
ret
.cfi_endproc
Which looks pretty good to me (just returns -1).
But:
constexpr
int
stest()
{
return -1 << 0;
}
Yields:
test.cpp:103:1: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
stest()
^
test.cpp:105:15: note: left shift of negative value -1
return -1 << 0;
^
1 error generated.
What danger, or what non-portable behavior has been prevented here?
Might we reword [expr.shift]/p2 in terms of shifting 1 bits off of the most significant end, instead of in terms of E1*2^E2?
The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. <del>If E1 has an unsigned type, the value of the result is E1 × 2^E2, reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1 × 2^E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise<del><ins>If E1 has signed type and the result would have fewer non-zero bits than E1</ins>, the behavior is undefined.
Indeed, the conflation of bit shifts with multiplying / dividing by 2 has been a never-ending source of bugs over the decades. Let's just say no to that.
Howard
Received on 2013-10-26 20:08:57