2) Is it undefined behavior to simply have a reference to an object that no longer exists, even if that reference is not used?
No. The rule that references must refer to a valid object applies when the reference is inintialised. The rule has already been quoted in the comments: "A reference shall be initialized to refer to a valid object or function." This rule has not been violated in your program, and there are no other restrictions on references requiring them to refer to valid objects or functions after initialization.
The standard has a few examples involving dangling references, such as [class.temporary]5.4:
struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };
S* p = new S{ 1, {2,3} }; // Creates dangling reference.
and doesn't say for any such example that the mere existence of a dangling reference is invalid. Although it's never explicitly stated as allowed, the absence of any rule prohibiting it is enough to allow it.
1) Is it undefined behavior to return a reference to a temporary, even if that reference is not used?
No. The construction of the result (the initialisation of the reference) happens in the context of the called function. There can even be extra code in the called function that runs after the construction of the result: destructors for local objects run after the construction of the result has finished. Since the reference is initialized to a valid object, this is just like your second question, that same rule still hasn't been violated.
3) Is it undefined behavior to combine these?
Yes. In your example, p
is not initialised to refer to a valid object or function. As you can tell from the comments on your question, there are issues with the wording in the standard, but the intent of this rule pretty clearly is that if it is violated, the behaviour is undefined.
int& ret = func()
– Lasallei
. – Brewhousei
– Brewhouse