Adding the [[clang::assert_nrvo]] variable attribute

Hi, last year we shipped some significant improvements for NRVO: ⚙ D119792 [Clang] [P2025] Analyze only potential scopes for NRVO

In two words, the NRVO is an optimization where the resulting variable is built in-place on the caller side, and the compiler doesn’t call copy/move ctors and doesn’t even care if these ctors are present at all (!)

Also last year I saw that people who develop the Carbon language gave the users freedom to assert whether their variable will have NRVO: carbon-lang/docs/design at trunk · carbon-language/carbon-lang · GitHub

I suggest to add the new [[clang::assert_nrvo]] attribute that will fail compilation (or emit a warning) if the variable actually isn’t marked as nrvo in the AST.

It will have use cases. I have seen many cases where senior people wrote:

std::optional<BigStruct> foo() {
    BigStruct b;
    // ...
    return b; // expecting the NRVO
}

But it doesn’t do NRVO because it does the implicit conversion from the const BigStruct& type to the std::optional<BigStruct> type. It should have been return std::move(b); So the new attribute could catch this.
Also it could catch cases with long functions where there is a break of the NRVO conditions in the middle of the function.

There is the list of all variable attributes: Attributes in Clang — Clang 17.0.0git documentation
I see some really minor attributes. How do you think, can I add such an attribute? How to make decision whether people really need it in the Clang compiler?

2 Likes

We add attributes for all kinds of reasons (improved diagnostics, improved optimizations, target-specific behaviors, coding standards, etc), so the question of whether to add a new one really boils down to whether it’s expected to be used by enough users to justify adding it to the compiler.

It’s not clear to me what you expect to put the attribute on. Is this a function attribute that asserts all return paths will perform NRVO? Or is it a variable attribute that asserts the marked variable must be returned via NRVO?

(If it’s a variable attribute, it makes me wonder what the behavior is if the local variable is never returned from the function at all, or if the return statement has a non-DeclRefExpr expression involving the variable as in return var + 12;, etc.)

In either case, there’s a question of “how many users will know to use this attribute?” Do you have evidence that this attribute will get used in practice? (For example, are libc++ folks interested in this attribute to help with standard library guarantees? That sort of thing.)

Have you considered adding a remark? We could use a -Rnrvo to emit a remark when it fails. -Rmodule-build, -Rmodule-import and similar are examples you can already find in the codebase.

From the perspective of a user, the attribute looks a little odd to me. Since I would only assert for functionality instead of such optimization. Because I feel bad that the programmers care too much about the optimizations which they can’t/shouldn’t control.

But it doesn’t do NRVO because it does the implicit conversion from the const BigStruct& type to the std::optional<BigStruct> type. It should have been return std::move(b); So the new attribute could catch this.

This explanation looks a little bit odd. Since I remember the spec says the compilers can (but not required to) perform NRVO. So I would love to say the compiler doesn’t do NRVO because it would love to.

And I am afraid that someday some project become broken after they update the compiler. Since the language didn’t promise anything about NRVO.

Thank you all for the answers! It is really a controversional feature and therefore should not be added I guess.

@AaronBallman

Or is it a variable attribute that asserts the marked variable must be returned via NRVO?

Yes, I thought it would be a variable attribute.

it makes me wonder what the behavior is if the local variable is never returned from the function at all

It would emit either a warning or an error, depending on the flag.

or if the return statement has a non-DeclRefExpr expression involving the variable as in return var + 12; , etc.

The return var + 12 breaks the NRVO (because this is an rvalue), therefore the variable wouldn’t have the nrvo attribute, so it would be a warning/error.

Do you have evidence that this attribute will get used in practice?

That’s the right point. I found out that few programmers aware of the NRVO. Even the compilers don’t cover all the obvious NRVO cases yet. Unfortunately the attribute wouldn’t get much popularity.

@ChuanqiXu

Because I feel bad that the programmers care too much about the optimizations which they can’t/shouldn’t control.

Since I remember the spec says the compilers can (but not required to) perform NRVO. So I would love to say the compiler doesn’t do NRVO because it would love to.

And I am afraid that someday some project become broken after they update the compiler. Since the language didn’t promise anything about NRVO.

This is a very valid point. So I actually find it hilarious that the C++23 standardized the [[assume(expr)]] attribute literally saying the compiler may or may not do whatever it wants to.

Like the users ought to write unit tests for assembler/LLVM IR to check that a new compiler update doesn’t break things.

1 Like