intVal is an assignment expression defined in 5.17 [exp.ass] in the standard. The grammar rules for an assignment expression are quite complex, depending on several other grammar rules, but basically you need a modifiable lvalue on the left side of the = operator and a prvalue expression on the right side.
When
intVal = foo();
an expression on RHS is an lvalue of type int , so a conversion occurs with a conversion of lvalue-to-r ... this is barely a conversion, since the value does not change and does not make the type (except that for base types, cv qualifiers are deleted, therefore, if lvalue is of type const int , prvalue will be of type int ). [conv.lval] says
The value gl (3.10) of a non-function type without an array T can be converted to prvalue. [...] If T is a non-class type, the prvalue type is a cv-unqualified version of T Otherwise, the prvalue type is T [...] the value contained in the object specified by glvalue is the result of prvalue.
Thus, prvalue is of type int and has the same value as foo() , i.e. the same value as the variable from which the link is returned.
Assignment rules express:
In a simple assignment ( = ), the value of an expression replaces the value of the object referenced by the left operand.
Thus, the value of intVal will be replaced by the value of prvalue. Rules continue:
If the left operand is not of the class type, the expression is implicitly converted (section 4) to the cv-unqualified type of the left operand.
Since int not a type of class (and therefore does not have operator= overloaded, it just uses the built-in assignment operator), the assignment converts RHS to int , which is the type that it already has in your case.
Thus, the value of intVal set equal to the value of prvalue, which we called the value of the expression glvalue foo() , that is, the value of the variable bound to the link.
Note that the lvalue-to-rvalue conversion has nothing to do with the fact that RHS is a reference. The same thing happens here:
int val = 0; intVal = val;
val is an lvalue of type int , so it is converted to a prvalue of type int , and the value of intVal set to the value of this value.
Rules are expressed in terms of the expression โcategory of valueโ (that is, an lvalue or rvalue), not this link or not. Any "dereferencing" of the required link is implicitly and invisibly performed by the compiler to implement the desired behavior.