The abstract operational semantics from ISO/IEC 9899 says:
6.5.7 Bitwise shift operators --- Semantics
3 .... ... . If the value
of the right operand is negative or is greater than or equal to the
width of the promoted left operand, the behavior is undefined.
In your case, disassembling and seeing what happens, we see so:
[root@arch stub]# objdump -d a.out | sed '/ <main>/,/^$/ !d'
00000000004004f6 <main>:
4004f6: 55 push %rbp
4004f7: 48 89 e5 mov %rsp,%rbp
4004fa: 48 83 ec 10 sub $0x10,%rsp
4004fe: c7 45 fc 07 00 00 00 movl $0x7,-0x4(%rbp)
400505: b8 20 00 00 00 mov $0x20,%eax
40050a: 89 c1 mov %eax,%ecx
40050c: d3 65 fc shll %cl,-0x4(%rbp) <<== HERE IS THE PROBLEM
40050f: 8b 45 fc mov -0x4(%rbp),%eax
400512: 89 c6 mov %eax,%esi
400514: bf b4 05 40 00 mov $0x4005b4,%edi
400519: b8 00 00 00 00 mov $0x0,%eax
40051e: e8 cd fe ff ff callq 4003f0 <printf@plt>
400523: b8 00 00 00 00 mov $0x0,%eax
400528: c9 leaveq
400529: c3 retq
40052a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
The generated code tries indeed to shift, but the shll %cl,-0x4(%rbp) (shift left of a long) has no effect.
The undefined behaviour in this case lies in assembly, namely in SHL operation.