Yet another clang/gcc discrepancy regarding ODR usage? - c++

Why does this code compile with GCC (4.9 and 5+), but not with clang (3.5-3.9)?
void test(const int&) { }
int main() {
const int x = 42;
auto f = []{ test(x); };
}
I have some vague idea that the discrepancy has to do with ODR (One Definition Rule) usage, but I don't understand that well enough to figure out what's going on here.

x is odr-used because it's bound to a reference (test's parameter). It therefore must be captured ([expr.prim.lambda]/13):
If a lambda-expression or an instantiation of the function call
operator template of a generic lambda odr-uses ([basic.def.odr]) this
or a variable with automatic storage duration from its reaching scope,
that entity shall be captured by the lambda-expression.
Violations of this rule, like all other rules in the standard that doesn't say "no diagnostic required" or "undefined behavior", require a diagnostic.
GCC, unfortunately, performs constant folding too early, before it could tell whether it's an odr-use or not. This can lead to problems such as [&]()->const int & { return x; } returning a dangling reference.

T.C. has the right diagnosis, here's a clearer bit of legal code where clang does the right thing and gcc doesn't:
#include <iostream>
void test(const int&a) { std::cout << "in test() -- " << &a << "\n"; }
int main() {
const int x = 42;
std::cout << "in main() -- " << &x << "\n";
auto f = [&]{ test(x); };
f();
}
gcc prints different addresses for a capture-by-reference variable than the original!

Related

constexpr and std::cout working on function but not in lambda

Why constexpr does not work with std::cout, but works with printf?
#include <iostream>
constexpr void f() { std::cout << ""; } //error
constexpr void g() { printf(""); } //ok
And why std::cout works with lambdas constexpr?
#include <iostream>
int main () {
auto h = []() constexpr { std::cout << ""; }; //ok
}
Technically, it doesn't work with any of them.
From [dcl.constexr]:
For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, a constant initializer for some object ([basic.start.static]), the program is ill-formed, no diagnostic required.
f() and g() are never constant expressions (neither std::cout << x nor printf() are constexpr functions), so the constexpr declaration is ill-formed. But the compiler isn't required to diagnose this (in this case, it may be easy, but in the general case... not so much). What you're seeing is that your compiler was able to diagnose one problem but not the other.
But they're both wrong.
It doesn't. You need to use it to force a compile time error.
constexpr int a = f(), 0; // fails
constexpr int b = g(), 0; // fails
constexpr functions that never produce a constant expression are ill-formed; no diagnostic required. This means that compilers do a best effort check to see if that is the case, but your program already has an error either way. Seems like gcc can't see that printf is not a constant expression. clang errors at the definition.

C++ "return" the result of an expression

Is there any difference between the evaluation of expressions between the two return statements below, based on the extra parenthesis?
return a++ *(-b+123.456)/999.12344;
vs
return (a++ *(-b+123.456)/999.12344);
Programming Language C++
Standards CPP 98'ish (Before C++11)
Hope the question is clear. Expectation is to evaluate the expression in full.
Sloppy speaking x is the same as (x) (see this answer for the "striclty speaking" answer ;). Adding parentheses around the full expression does not change anything about operator precedence.
PS: It has an obscure impact on return value optimization (see this answer for the details). Though, it definitely has no impact on the value that is returned.
There are differences. Using parentheses will obviate return value optimisation.
If, for example, a and / or b were objects with all suitable operators overloaded, then using parentheses could suffer you the overhead of an object value copy.
For plain-old-data there is no difference, subject to the C++11 abomination
decltype(auto) ub_server() { int a; return (a);}
which actually gives you a dangling reference.
In summary: Don't use the enclosing parentheses unless you want some of the above behaviour, and possibly only then with a supporting comment.
Is there any difference between the evaluation of expressions between the two return statements below, based on the extra parenthesis?
No; the parentheses are completely redundant in this case.
An expression expr is actually not the same as an expression (expr), and you can observe this with return because copy/move elision is inhibited in the latter case:
#include <iostream>
struct T
{
T() { std::cout << "T()\n"; }
T(const T&) { std::cout << "T(const T&)\n"; }
T(T&&) { std::cout << "T(T&&)\n"; }
~T() { std::cout << "~T()\n"; }
};
T foo()
{
T t;
return t;
}
T bar()
{
T t;
return (t);
}
int main()
{
std::cout << "Test 1\n------\n";
foo();
std::cout << '\n';
std::cout << "Test 2\n------\n";
bar();
}
Output:
Test 1
------
T()
~T()
Test 2
------
T()
T(T&&)
~T()
~T()
(live demo)
You can probably observe the same result before C++17 because compilers have always tried to optimise return values. Even in your standard, C++98, you can probably observe that the copy constructor isn't invoked in the first case.
But, hey, none of that is relevant for a simple arithmetic expression.

In class static const ODR

I am a bit confused by the static in-class initialization of a const member. For example, in the code below:
#include <iostream>
struct Foo
{
const static int n = 42;
};
// const int Foo::n; // No ODR
void f(const int& param)
{
std::cout << param << std::endl;
}
int g(const int& param)
{
return param;
}
template<int N>
void h()
{
std::cout << N << std::endl;
}
int main()
{
// f(Foo::n); // linker error, both g++/clang++
std::cout << g(Foo::n) << std::endl; // OK in g++ only with -O(1,2 or 3) flag, why?!
h<Foo::n>(); // this should be fine
}
Live example
I do not define Foo::n (the line is commented). So, I expect the call f(Foo::n) to fail at link time, and indeed it does. However, the following line std::cout << g(Foo::n) << std::endl; compiles and links fine only by gcc (clang still emits a linker error) whenever I use an optimization flag such as -O1/2/3.
Why does gcc (tried with gcc5.2.0 and gcc 4.9.3) compile and link the code when the optimization is turned on?
And am I correct to say that the only usage of in-class static const members is in constant expressions, such as template parameters like in the h<Foo::n> call, in which case the code should link?
I suppose that the compiler performs the following actions during the optimization:
The value const static int n is inlined everywhere. No memory is allocated for the variable n, references to it becomes invalid. The function f() need a reference to n so the program is not compiled.
The function g is short and simple. It is effectively inlined and optimized. After the optimization, the function g does not need a reference to n, it just returns constant value 42.
The solution is to define the variable outside the class:
struct Foo
{
const static int n;
};
const int Foo::n = 42;
ODR violations do not require a diagnostic, from the draft C++ standard standard section 3.2 [basic.def.odr] (emphasis mine going forward):
Every program shall contain exactly one definition of every non-inline
function or variable that is odr-used in that program; no diagnostic
required.
So inconsistent behavior at different optimization levels is perfectly conformant behavior.
Informally a variable is odr-used if:
its address is taken, or a reference is bound to it, and a function is odr-used if a function call to it is made or its address is taken. If an object or a function is odr-used, its definition must exist somewhere in the program; a violation of that is a link-time error.
So both f and g will be odr-uses and require a definition.
The relevant C++14 quote on odr-use would be from section [basic.def.odr]:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying
the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any nontrivial
functions and, if x is an object, ex is an element of the set of potential results of an expression e,
where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression [...]
The wording in C++11 is similar, the changes from C++11 to C++14 are reflected in defect report 712.
Before C++11 it is a bit more complicated but in principle the same for this case.
Formally, ODR violations are undefined behaviour, so the compiler may exhibit any behaviour it likes. That's why the behaviour changes with optimization level and compiler- the compiler has no obligation to maintain a particular behaviour.
There is no definition at all. GCC 4.9.2 doesn't compile and link that with any flags.
Note, that:
const static int n = 42;
is a declaration and initializer, but not a definition.

Why is g++ allowing me to treat this void-function as anything but?

Why does the following compile in GCC 4.8 (g++)? Isn't it completely ill-formed?
void test(int x)
{
return test(3);
}
int main() {}
I'm trying to use the result of calling test, which does not exist
I'm trying to return a value from test
Both should be fundamentally impossible — not just UB, as far as I can recall — with a void return type.
The only warning I get is about x being unused, not even anything about a non-standard implicit return type being added.
Live demo
That's allowed by the standard (§6.6.3/3)
A return statement with an expression of type void can be used only in functions with a return type of cv void; the expression is evaluated just before the function returns to its caller.
As to why GCC allows it - sure because the Standard requires it to be valid. Building the transitive closure to the rationale of the rule in the Standard, I'm pretty sure that GCC allows this because it's useful in the event of templates
template<typename F>
typename std::result_of<F()>::type call(F f) {
return f();
}
int main() {
std::cout << call([]{ return 42; }) << std::endl;
call([]{ std::cout << "I'm just an outputtor!" << std::endl; });
}
As you see, call did not need to do a special case for void in the return statement. Sort of similar to how x.~T() is allowed even if T ends up as int.

Is it legal to take the address of a const lvalue reference?

#include <iostream>
int foo()
{
return 0;
}
int main()
{
const int& a = foo();
std::cout << &a << std::endl;
}
In this code, a binds to a rvalue. Is it legal to take its address? (And by legal I mean: in the code ill-formed? Am I causing an undefined behaviour?)
This is fine. In C++11 you can even do this:
int&& a = foo();
a = 123;
You can kind of think about temporaries like this (conceptually and in general):
x = func(); // translated as:
auto __temporary = func();
x = __temporary;
__destruct_value_now_and_not_later(__temporary);
Except if x is the definition of a reference type, the compiler notes that you're purposefully referring to the temporary value and extends its lifetime by removing the early destruction code, making it a normal variable.
Yes. Until the variable a goes out of scope, the temporary it captures is valid. Herb Sutter can explain it better.