Here is what happens:
x = self.conv1(input) # main branch
# x is a Variable containing a tensor whose value is the output of conv1

x_p = self.conv1_p(x) # another branch
# Here, x is used as input to conv1_p, since conv1_p will need the value of x
# to compute the backward pass, it marks it to be saved for the backward pass.

x += some_layer # main branch
# Here you try to modify the tensor x inplace, if you do so, it would not contain
# the output of conv1 anymore, and conv1_p would not be able to compute its
# backward, so this is forbidden

In you second example, everything is the same but the last line.
When you do x = x + some_layer, you create a new tensor that will contain the result of x + some_layer then assign this tensor to the python variable x. Here the Tensor x that contains the output of conv1 has not been changed, and so conv1_p can compute it’s backward without problem.
The difference between x = x + and x += is that the first operation creates a new tensor while the second one does not create any new Tensor. So the second one can be considered a small optimization speed and memory wise, but is not always possible.