On Tue, 26 Nov 2024 at 16:15, Michael Matz <m...@suse.de> wrote: > > Hello, > > thanks for bearing with me :) > > On Tue, 26 Nov 2024, Jonathan Wakely wrote: > > > Being a member function makes no difference, but yes, I'm specifically > > talking about the case of calling a constexpr function. > > > > constexpr int bla() { return 2; } > > int foo (void) { > > const int x = bla(); > > int y = bla(); > > return x + y; > > } > > > > At -O0 this is one instruction smaller due to the const. Adding const > > to y removes another instruction. > > Hmm hmm. But that is due to how x and y are used, not in how the RHS of > their initializers is evaluated (in the above case both initializers are > compile-time evaluated also at O0 in gcc). I.e. on -O0 the same > difference occurs for > > const int x = 42; > int y = 42; > return x + y; > > ('y' but not 'x' will be stored and reloaded from stack on O0, that's the > additional insn, which matches the abstract machine for non-const values).
Aha, thanks, that makes sense. > But I was more interested in how the left hand side const qualifier > changes semantics for the rhs side in initializers, not how it changes > things in further uses of the initialized entity ... > > > Because in C++ when a const int is initialized by a constant > > expression that const int becomes an integral constant: > > ... and I think that's the crucial thing I was missing: a const int X may > or may not be an integral constant, depending on how it's initialized. > So it's rather that the kind of the RHS initializer influences the kind of > the LHS (as is proper), but only when that LHS is const. Yes, that's a good way to look at it. > Okay, I can > live with that :-) > > ... hmm ... > > But even then it only has observable effects when that X is used > in contexts where an integral constant is required (which wasn't the case > in the deque example, perhaps that confused me). Ah, there's actually one other factor that affects it, which I forgot about. Because C++98 doesn't have the 'constexpr' keyword, it means that the bla() function can't be constexpr, so in C++98 we have: #if __cplusplus >= 201103L constexpr #else inline #endif int bla() { return 2; } int foo (void) { const int x = bla(); int y = bla(); return x + y; } And now for -O0 it really does make a difference whether we have two separate calls to bla() or if we call it once and store the result in a local variable. So the 'const int' doesn't really matter for any -On level, as you say, but just avoiding two separate uses of the __deque_buf_size function is worthwhile for -std=c++98 -O0 You were right to be triggered, I was wrong to say that making it a constant expression mattered. For C++98 it's not a constant expression (because the function is just 'inline' but not 'constexpr') and for C++11 the fact it's 'constexpr' is enough for it to be constant-folded whether the LHS is const or not. > > In the bla() example above, the call bla() is a constant expression > > when used to initialize a const int, so the compiler is required to > > evaluate it at compile time. > > When used in contexts that doesn't require an integral constant I think a > distinction between evaluating at compile time or at run time can't be > observed. Agreed. > Obviously all required language rules, diagnostics and > constraints have to be observed (and for that the compiler is required to > look into the constexpr bla), but I think the ultimate > formation of the constant '2' (in our bla() case) can be done arbitrarily > complicated at run time, as long as '2' is the result and it's computed in > constant time and space. A long winded way of saying that I don't think > you can observe a distiction between calling bla() as given or using a > literal '2' in these contexts, no matter if x is const, constexpr, or > nothing. (let's ignore observation by assembly inspection :) ) > > > In pure C++11 code I'd make it more explicit and write: > > > > constexpr int x = blah(); > > I think I would have been less confused then, but still would have > wondered, as 'x' wasn't used in a constexpr-requiring context. I probably > would have thought "ahh, someone wanted to make really sure that 'blah' > will never be unnoticably rewritten to not be constant-evaluable anymore", > not "meh, a optimization hint that shouldn't rightfully be there for > a good compiler". > > Of course, with c++98 using 'const' here seems best now, so > thanks for the gcc-help@ lesson! ;-)