Mutable Member in a ConstExpr Object in C++11 - c++

In the C++14 Standard (ISO/IEC 14882:2014) the word "non-mutable" was added in Section 5.19, Paragraph 2 (emphasis mine):
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:
[...]
an lvalue-to-rvalue conversion (4.1) unless it is applied to
[...]
a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable sub-object of such an object, or
Therefore, this code is not correct in C++14:
class A {
public:
mutable int x;
};
int main(){
constexpr A a = {1};
constexpr int y = a.x;
return 0;
}
However, is it correct in C++11?
This is the Defect Report (CD3) 1405 where they proposed to add non-mutable:
Currently, literal class types can have mutable members. It is not clear whether that poses any particular problems with constexpr objects and constant expressions, and if so, what should be done about it.
So I would say it is correct C++11 code. Nevertheless, I tried Clang and GCC with -std=c++11 and both output an error saying mutable variables are not allowed in a constant expression. But that constraint is something added in C++14, it was not in C++11.
Does anyone know if that code is correct in C++11?
See also Defect Report (CD3) 1428.

It's C++11 defect report, then C++11 need to be fixed. Only those issues with DR, accepted, DRWP, and WP status are NOT part of the International Standard for C++.
C++11 conformed compiler must implement that DR.
For example, this pair of examples is changed because of DR 1579:
gcc 6.1.0
gcc 4.9.3
This example was taken from: Why this C++ program gives different output in C++11 & C++14 compilers

Related

Can one volatile constexpr variable initialize another one in C++?

C++ standard allows constexpr volatile variables per defect report 1688, which was resolved in September 2013:
The combination is intentionally permitted and could be used in some circumstances to force constant initialization.
It looks though that the intention was to allow only constinit volatile, which was not available before C++20.
Still the current compilers diverge in treatment of constexpr volatile in certain circumstances. For example, this program initializes one such variable by the other one:
int main() {
constexpr volatile int i = 0;
constexpr volatile int j = i;
return j;
}
It is accepted in GCC and MSVC, but Clang complains:
error: constexpr variable 'j' must be initialized by a constant expression
constexpr volatile int j = i;
^ ~
note: read of volatile-qualified type 'const volatile int' is not allowed in a constant expression
constexpr volatile int j = i;
Online demo: https://gcc.godbolt.org/z/43ee65Peq
Which compiler is right here and why?
Clang is correct. The initialization of j from i requires that an lvalue-to-rvalue conversion be performed on i, but according to [expr.const]/5.9, an lvalue-to-rvalue conversion on a volatile glvalue is never permitted inside a constant expression. Since i is a constexpr variable, it must be initialized by a constant expression.
I have no idea why GCC and MSVC choose not to enforce this rule, other than that all C++ compilers are perpetually short-staffed and can't implement everything they're expected to.
The defect report you linked shows it should not work, so Clang is correct.
(...) “a non-volatile object defined with constexpr” (...) is permitted but that such a variable cannot appear in a constant expression. What is the intent?
But more interesting is: why does Clang care while other compilers don't?
In my opinion, this happened because of JF Bastien, a very influential figure in the world of Clang / LLVM, that personally dislikes volatile :)
He has been proposing to remove it from the language for a long time. So if it was allowed to ban volatile somewhere, he probably spared no effort to make it so. If for no other reason than simply to prevent people from writing code that will have to be rewritten if his proposal is eventually accepted.
He also made a presentation at CppCon about his deprecation proposal, if you want to know his reasoning.

constexpr reference to non-const object

Is it permitted to declare a non-const reference as constexpr? Example code:
int x = 1;
constexpr int& r = x;
This is accepted by gcc and clang (I tried several current and past versions of both, back to C++11, and all accepted it). However I think it should not be accepted because C++14 [dcl.constexpr/9] says:
if a constexpr specifier is used in a reference declaration, every full-
expression that appears in its initializer shall be a constant expression
and x is not a constant expression.
The language in the latest C++17 draft of [dcl.constexpr] changed and doesn't even mention constexpr references explicitly any more, I can't make head nor tail of what it is trying to say about them.
Assuming that x has static storage duration, the lvalue expression x is a perfectly valid constant expression.
If you use x in a context that requires a prvalue, which causes the lvalue-to-rvalue conversion to be applied to it, then the resulting prvalue expression - call it TO_RVALUE(x) - would not be a constant expression, for obvious reasons. But in the case of reference binding, there is no such conversion.

Should decltype(foo(1)) instantiate the constexpr function template foo?

The following code compiles with with gcc and MSVC, but fails using clang I tested with clang-3.5 and current trunk).
template <typename T>
constexpr auto wrong = false;
template <typename T>
constexpr auto foo(const T t) -> int
{
static_assert(wrong<T>, "");
return {};
}
using F = decltype(foo(1));
int main() {}
clang instantiates the function body and stumbles over the static_assert. gcc and MSVC just look at the function declaration and ignore the static_assert in the body.
If you remove the constexpr, all compilers compile the code just fine.
Question:
Is decltype allowed to look into the function body if the return type is declared?
I am looking for a reference to the respective section in the standard.
History: As noted in comments, this issue was raised as CWG issue 1581. In a isocpp.org thread, Columbo argued that the code was valid because templates are never instantiated inside unevaluated operands, however on a clang bug report, "rsmith" countered that some decltype expressions definitely did require template instantiation.
The clang thread temporarily resolved the issue by coming up with their own (non-standard) criteria for when decltype would instantiate a constexpr template. Since version 4.0, clang does compile the code successfully.
Richard Smith of WG21 has started to address the issue as of November 2017, with P0859. This adds new text to [expr.const] which implement the behaviour of clang as discussed above:
An expression is potentially constant evaluated if it is:
a potentially-evaluated expression ([basic.def.odr]),
a constraint-expression, including one formed from the constraint-logical-or-expression of a requires-clause,
an immediate subexpression of a braced-init-list[ Footnote: Constant evaluation may be necessary to determine whether a narrowing conversion is performed ([dcl.init.list]). ],
an expression of the form & cast-expression that occurs within a templated entity[ Footnote: Constant evaluation may be necessary to determine whether such an expression is value-dependent ([temp.dep.constexpr]). ], or
a subexpression of one of the above that is not a subexpression of a nested unevaluated operand.
A function or variable is needed for constant evaluation if it is:
a constexpr function that is named by an expression ([basic.def.odr]) that is potentially constant evaluated, or
a variable whose name appears as a potentially constant evaluated expression that is either a constexpr variable or is of non-volatile const-qualified integral type or of reference type.
And [temp.inst] is modified to say that a template specialization is instantiated if its definition affects the semantics of the program, which means that it's needed for constant evaluation as defined above, even if it isn't actually needed, so to speak.
The ODR is modified to avoid Columbo's objection.
The recommended changes on that proposal do appear in N4727, which is a post-C++17 draft. So I assume they have been accepted even though the P0859 link and the CWG defect list don't say so yet.
Under these changes, your code decltype(foo(1)), the expression foo(1) is NOT potentially constant evaluated (because it does not match any of the bullet points above), so the template must not be instantiated, and the code, with a modification to avoid [dcl.constexpr]/6, should compile successfully.
(C++17 dcl.constexpr/6 says that a template is ill-formed NDR if there are no valid specializations; which is true for foo, however this can be fixed by adding template <> constexpr auto wrong<float> = true; for example).

What is a core constant expression in the C++11 Standard?

There are 11 references to the expression core constant expression in the latest draft of the C++11 Standard (N3690), and none of them defines what this entity is.
One can also find that the expression core constant expression is pretty well defined here , basically in the same terms that the Standard uses to define the expression conditional-expression.
Therefore, I would like to get some input on this issue, which seems to me, to be wrong in the Standard.
Now, assuming the definition in cppreference is correct I would also like to know why the following snippet compiles in Coliru and in Ideone, despite item (10) in the alluded definition?
#include <iostream>
int main()
{
const double x = 2.;
constexpr double y = x;
std::cout << y << std::endl;
}
I'm specifically thinking in terms of the lvalue to rvalue implicit conversion of variable x in the expression constexpr double y = x;, which is not covered by any of the clauses (a), (b) and (c) in item (10) referred above.
Thanks for the help.
N3690 does define the term "core constant expression in 5.19p2 [expr.const]:
A conditional-expression e is a core constant expression unless the
evaluation of e, following the rules of the abstract machine (1.9),
would evaluate one of the following expressions:
[list omitted]
The released ISO C++ 2011 standard defines it in the same section.
As for whether that's actually a definition, see also section 1.3, paragraph 3:
Terms that are used only in a small portion of this International
Standard are defined where they are used and italicized where they are
defined.
The standard also uses italics for syntactic categories such as conditional-expression, but "core constant expression" is a defined term, not a syntactic category (it's subtle, but you can tell by the use of spaces rather than hyphens to separate the words).
As for the sample code:
const double x = 2.;
constexpr double y = x;
my reading of the standard is that this is invalid, because x is not a core constant expression. It would be valid if x and y were of some integer or enumeration type, but there's no such permission for floating-point. An lvalue-to-rvalue conversion (converting the name of the object x to its value 2.0) is not permitted in a core constant expression unless it meets one of three listed criteria (see C11 5.19, 9th bullet, three sub-bullets).
This implies that the compilers that accept the above code without a diagnostic are non-conforming (i.e., buggy). (Unless I'm missing something, which is entirely possible.)
Which implies that http://en.cppreference.com/w/cpp/language/constant_expression is wrong. It says that a core constant expression may contain an lvalue-to-rvalue conversion of an lvalue that "has literal type and refers to an object defined with a constant expression (or to its subobject)". The actual standard has a stronger requirement: the object must be defined with constexpr. (Perhaps cppreference.com was based on an earlier draft?)
So the sample code could be made valid by changing it to:
constexpr double x = 2.;
constexpr double y = x;

Correct behaviour of trivial statements involving expressions with volatile variables?

Consider the following statements
volatile int a = 7;
a; // statement A
volatile int* b = &a;
*b; // statement B
volatile int& c = a;
c; // statement C
Now, I've been trying to find a point in the standard that tells me how a compiler is to behave when coming across these statements. All I could find is that A (and possibly C) gives me an lvalue, and so does B:
"§ 5.1.1.8 Primary expressions - General" says
An identifier is an id-expression provided it has been suitably declared (Clause 7). [..]
[..] The result is the entity denoted by the identifier. The result is an
lvalue if the entity is a function, variable, or data member and a
prvalue otherwise.
[..]
"§ 5.3.1 Unary operators" says
The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points.
clang and gcc
I tried this with clang++ 3.2-11 and g++ 4.7.3, and the first produced three reads in C++11 mode and zero reads in C++03 mode (outputting three warnings) while g++ only produced the first two, explicitly warning me that the third would not be generated.
Question
It is clear which type of value comes out of the expression, from the quoted line in the standard, but:
which of the statements (A,B,C) should produce a read from the volatile entity according to the C++ standard?
The G++ warning about the "implicit dereference" comes from code in gcc/cp/cvt.c which intentionally does not load the value through a reference:
/* Don't load the value if this is an implicit dereference, or if
the type needs to be handled by ctors/dtors. */
else if (is_volatile && is_reference)
G++ does that intentionally, because as stated in the manual (When is a Volatile C++ Object Accessed?) the standard is not clear about what constitutes an access of a volatile-qualified object. As stated there you need to force lvalue-to-rvalue conversion to force a load from a volatile.
Clang gives warnings in C++03 mode that indicate a similar interpretation:
a.cc:4:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
a; // statement A
^
a.cc:6:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
*b; // statement B
^~
a.cc:8:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
c; // statement C
^
3 warnings generated.
The G++ behaviour and the GCC manual seem to be correct for C++03, but there is a difference in C++11 relative to C++03, introduced by DR 1054 (which also explains why Clang behaves differently in C++)3 and C++11 modes). 5 [expr] p10 defines a discarded-value-expression and says that for volatiles the lvalue-to-rvalue conversion is applied to an id-expression such as your statements A and C. The spec for lvalue-to-rvalue conversion (4.1 [conv.lval]) says that the result is the value of the glvalue, which constitutes an access of the volatile. According to 5p10 all three of your statements should be accesses, so G++'s handling of statement C needs to be updated to conform to C++11. I've reported it as http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59314
This gcc document 7.1 When is a Volatile C++ Object Accessed? is relevant here, and I quote (emphasis mine going forward):
The C++ standard differs from the C standard in its treatment of volatile objects. It fails to specify what constitutes a volatile access, except to say that C++ should behave in a similar manner to C with respect to volatiles
The C and C++ language specifications differ when an object is accessed in a void context:
and provides this example:
volatile int *src = somevalue;
*src;
and continues by saying:
The C++ standard specifies that such expressions do not undergo lvalue to rvalue conversion, and that the type of the dereferenced object may be incomplete. The C++ standard does not specify explicitly that it is lvalue to rvalue conversion that is responsible for causing an access.
which should be referring to draft standard section 5.3.1 Unary operators paragraph 1 which says :
The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. [...]
and with respect to references:
When using a reference to volatile, G++ does not treat equivalent expressions as accesses to volatiles, but instead issues a warning that no volatile is accessed. The rationale for this is that otherwise it becomes difficult to determine where volatile access occur, and not possible to ignore the return value from functions returning volatile references. Again, if you wish to force a read, cast the reference to an rvalue.
so it looks like gcc is choosing to treat references to volatile differently and in order to force a read you need to cast to an rvalue, for example:
static_cast<volatile int>( c ) ;
which generates a prvalue and hence a lvalue to rvalue conversion, from section 5.2.9 Static cast:
The result of the expression static_cast(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue.
Update
The C++11 draft standard adds 5 Expressions paragraph 11 which says:
In some contexts, an expression only appears for its side effects. Such an expression is called a discarded-value expression. The expression is evaluated and its value is discarded. The array-to-pointer (4.2) and functionto-pointer (4.3) standard conversions are not applied. The lvalue-to-rvalue conversion (4.1) is applied if and only if the expression is an lvalue of volatile-qualified type and it is one of the following:
and includes:
— id-expression (5.1.1),
This seems ambiguous to me since with respect to a; and c; section 5.1.1 p8 says it is an lvalue and it is not obvious to me that it covers this case but as Jonathan found DR 1054 says it does indeed cover this case.