C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Named Return Value Optimisation [[nrvo]]

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Tue, 10 Feb 2026 16:05:00 +0100
wt., 10 lut 2026 o 15:09 Alejandro Colomar
<une+cxx_std-proposals_at_[hidden]> napisał(a):
>
> Hi Marcin,
>
> On 2026-02-10T14:44:03+0100, Marcin Jaczewski wrote:
> > > > > > > alx_at_devuan:~/tmp$ cat nodiscard.c++
> > > > > > > [[nodiscard]] int f(void);
> > > > > > >
> > > > > > > int
> > > > > > > main(void)
> > > > > > > {
> > > > > > > typeof(int (void) ) *fp1;
> > > > > > > typeof(int (void)[[nodiscard]]) *fp2;
> > > > > > >
> > > > > > > fp1 = &f; // I would expect a diagnostic here.
> > > > > > > fp1();
> > > > > > >
> > > > > > > fp2 = &f;
> > > > > > > fp2();
> > > > > > > }
> > > > > > > alx_at_devuan:~/tmp$ g++ -S -Wall -Wextra nodiscard.c++
> > > > > > > nodiscard.c++: In function ‘int main()’:
> > > > > > > nodiscard.c++:7:38: warning: ‘nodiscard’ attribute can only be applied to functions or to class or enumeration types [-Wattributes]
> > > > > > > 7 | typeof(int (void)[[nodiscard]]) *fp2;
> > > > > > > | ^
> > >
> > > [...]
> > > > > No, that was not the point. The point is that the conversion in
> > > > > fp1 = &f;
> > > > > discards an attribute from the function type, and thus results in calls
> > > > > through that function pointer to not have a diagnostic when the return
> > > > > value is discarded. This is a hole in the rules.
> > > > >
> > > > > And the diagnostic you see in fp2 is in fact another hint that the
> > > > > design of [[nodiscard]] was bogus. That code should be accepted, and it
> > > > > should be the only way of storing a function pointer that holds &f. If
> > > > > that's not accepted, there is no way of using [[nodiscard]] safely.
> > > > >
> > > >
> > > > But what does this have to do with ignorability of attributes?
> > > > It's possible that you could not add the "not-ignorable" attribute there anyway.
> > > > ```
> > > > std::is_same<int, [[foo]] int>
> > > > ```
> > > > how C++ should handle it? even in case where it can't ignore this attribute.
> > > >
> > > > Only solution I see is that `fp1` itself should have `[[nodiscard]]`,
> > >
> > > Yes; it should be like fp2, and the attribute should be part of the type
> > > (and thus we should have no diagnostic in line 7).
> > >
> >
> > I mean something diffrent, I word this wrongly.
> > I means that variable itself should have attribute like:
> >
> > ```
> > typeof(int (void)) *fp2 [[nodiscard]];
> > ```
> >
> > And this would fit the definition of `f` as its attribute is linked to
> > name not to its type.
> > And this will be fine in the current paradigm.
>
> That would be the wrong choice. The attribute should be part of the
> type, to make sure type conversions are okay.
>
> Let's make it more complex:
>
> [[nodiscard]] int f(void);
> int g(void);
>
> void h(int (*)(void) );
> void i(int (*)(void)[[nodiscard]]);
>
> int
> main(void)
> {
> h(&f); // This should be diagnosed.
> i(&f);
> h(&g);
> i(&g);
> }
>
> Essentially, [[nodiscard]] should behave like a function qualifier, so
> that pointers to functions should be able to gain it but not discard it.
>
> Otherwise, we have a hole.

But this exactly same case I showed, if you change attribute to argument:
```
void i(int (*arg [[nodiscard]] )(void));
```
This is the property of the argument of the `i` function.


Only problem start when you try pass `i` itself to another function:

```
void foo(void (*)(int (*)(void)));
```

Here its become probably very painful to handle it but how many times
you need arbitrary nesting?
Besdied, we can avoid all this by baning both cases like:

```
                 h(&f); // error
                 i(&f); //error too
                 h([[trust_me_bro]]&f); // ok, explicit "cast"
                 i([[trust_me_bro]]&f); // ok, explicit "cast"
```

>
> > > > and this could be still ignorable.
> > >
> > > In part, this is a problem because either
> > >
> > > a) ignorability of attributes is the problem
> > > or
> > > b) [[nodiscard]] should not be ignorable, and should be replaced by a
> > > non-ignorable attribute.
> > >
> > > And if b) is chosen, then few very ignorable attributes would remain;
> > > so that ignorability of attributes would render attributes DoA. *The*
> > > truly ignorable attribute is [[maybe_unused]].
> > >
> > I can imagine many others that could work fine and be enforced by the compiler
> > but safely ignored if the compiler does not bother implementing them.
> >
> > ```
> > int* foo(int* b [[restrict(A,B)]], int* c [[restrict(C)]])
> > [[restrict(A,B,C)]]
> > {
> > *b += 2;
> > *c += 2;
> > return *b < *c ? b : c;
> > }
> > ```
> >
> > Now if the compiler regonzie this attribute then he could only do 2
> > loads as pointers should not overlap.
> > If not, then it only generates less optimal code. if the programmer
> > lied then we get UB, same as `[[noreturn]]`.
>
> restrict is terrible, and your suggested [[restrict]] is similarly
> terrible.
>
> A [[restrict]] replacement of restrict should prioritize diagnostics
> over optimizations. Thus, it would end up being similar to
> [[nodiscard]].
>
> Tricky question: should the following code result in a diagnostic?
>
> alx_at_devuan:~/tmp$ cat restrict.c
> void f(int *p [[restrict]], int **pp [[restrict]]);
>
> int
> main(void)
> {
> int i = 42;
> int *p = &i;
>
> f(p, &p);
> }

At least my "restric" have explicit arbitrary groups, and would reject
this code as values are from the same "group".
Beside I would here ask programet to be explicit:

```
f(p, [[trust_me_restric]]&p); //otherwise diagnostic
```

overall I would use my restic too to handle life time ranges in program like:
```
[[restrict(stack)]]
[[restrict(temporal)]]
[[restrict(global)]]
```

Of course it will be painful when you use multiple nested `*` but we
probably should not mix diffrent group too much.

>
> Similarly tricky question: should the following code result in a
> diagnostic?
>
> alx_at_devuan:~/tmp$ cat restrict.c
> void f(int *restrict p, int **restrict pp);
>
> int
> main(void)
> {
> int i = 42;
> int *p = &i;
>
> f(p, &p);
> }
>
>
> Cheers,
> Alex
>
> --
> <https://www.alejandro-colomar.es>

Received on 2026-02-10 15:05:16