The copy constructor can have both forms(*) as below:
A(const A& rhs);
Both are perfectly valid and it is pretty easy to forget the 'const' for the rhs argument. The compiler accepts it as a perfectly valid syntax thinking that is what your intent was. But the above two are a bit different from each other. The first one rejects to work with/copy from parameters that are not const objects of type A as well as temporaries. So, if you tried something like this:
const A const_a;
A copy_const_a(const_a); //ERROR!
A copy_from_temp(A(/*some arguments*/)); //ERROR!
A copy_from_return_val(somefunc_return_A_by_val); //ERROR!
//any other forms that might want to create copies out of const or temorary objects
the compiler will just shout at you at the appropriateness of the copy constructor you wrote. And if you by any chance overlooked the argument for your it assuming it be correct, you would most certainly lose some of your precious time thinking probably some of your member objects are not copy constructible or there's some issue of that sort.
This brings us to the primary point of const correctness. Make things const, declare them const unless you explicitly wanted them to be non-const. I know some people who have the opinion that this should have been implicit by the language and to make something non-const there should have been a keyword i.e. there were a keyword 'mutable' (not in the sense that it is used in the language currently) or something similar to let know that the object is non-const. But it's probably too late for it. :-)
(*) Or for that matter any of the 4 forms as mentioned below:
A(A& rhs /*, either no other args or all default args*/);
A(const A& rhs /*, either no other args or all default args*/);
A(volatile A& rhs /*, either no other args or all default args*/);
A(const volatile A& rhs /*, either no other args or all default args*/);