I am not an expert on this, but I do think I have an idea of what's going on: AFAIK the state that m//gc keeps is attached to each string (pos). See the output of the following, just your test cases with debugging added:
use warnings;
use strict;
use Carp;
use Devel::Peek;
sub parse {
Dump $_[0];
${$_[0]}=~/\Gfoo/gc or confess;
}
warn "##### Case 1 #####\n";
parse \(''.'foo') for 1..2;
warn "##### Case 2 #####\n";
parse \('foo') for 1..2;
In "Case 1", the dot operator (concat) appears* to create a new string on each execution of the loop. In "Case 2", the same string (same memory address etc.) is passed to the function each time, so m/\G.../gc keeps its state, and so the second call fails.
As for B::Deparse, from its docs:
The output of B::Deparse won't be exactly the same as the original source, since perl doesn't keep track of comments or whitespace, and there isn't a one-to-one correspondence between perl's syntactical constructions and their compiled form, but it will often be close.
* Update: Added the "appears to", since my further investigation below has made me uncertain as to what is going on the exact technical explanation is.