What you are seeing is a mix of copy elision and an actual copy being made.  Since f takes a by value, It needs to copy A() into a. The compiler sees this copy really isn't needed, so it elides that and instead directly constructs a so you don't see any call.  In the body of f when you return a;, it needs to copy a into the return value.  Since a is a lvalue, A(A&) is a better match than A(const A&) so you see the call to the non const copy constructor.  Then a1 needs to be initialized from f's return value.  Again copy elision comes into play again and instead of seeing a copy it just directly puts the return value into a1's storage.  
So, elide, non-const copy, elide, which leaves the output with just copy non const
You get an error when you remove A(const A&) because even though those copies were elided, C++ still required there to be copy constructor until C++17.
If you compile with gcc or clang and use -fno-elide-constructors you can actually see those copies.  You can see that in this live example.  Note that I used -std=c++11 to turn off C++17's guaranteed copy elision