Document: | WG21 N3914 |
Author: | William M. (Mike) Miller Edison Design Group, Inc. |
Date: | 2014-02-14 |
The following issue resolutions, in addition to those in "ready" and "tentatively ready" status in document N3833, have been approved by the Core Language Working Group to be applied to the DIS.
1466. Visible sequences of side effects are redundant
Proposed resolution:
Change 1.10 [intro.multithread] paragraph 14 as follows:
The visible sequence of side effects on an atomic object M, with respect to a value computation B of M, is a maximal contiguous sub-sequence of side effects in the modification order of M, where the first side effect is visible with respect to B, and for every side effect, it is not the case that B happens before it.The value of an atomic object M, as determined by evaluation B, shall be the value stored by someoperation in the visible sequence of M with respect to Bside effect A that modifies M, where B does not happen before A. [Note:It can be shown that the visible sequence of side effects of a value computation is unique givenThe set of such side effects is also restricted by the rest of the rules described here, and in particular, by the coherence requirements below. —end note]
Change 1.10 [intro.multithread] paragraph 20 as follows:
[Note: Thevisible sequence of side effectsvalue observed by a load of an atomic depends on the “happens before” relation, which depends on the values observed by loads of atomics, which we are restricting here. The intended reading is that there must exist an association of atomic loads with modifications they observe that, together with suitably chosen modification orders and the “happens before” relation derived as described above, satisfy the resulting constraints as imposed here. —end note]
Change 1.10 [intro.multithread] paragraph 22 as follows:
[Note: Compiler transformations that introduce assignments to a potentially shared memory location that would not be modified by the abstract machine are generally precluded by this standard, since such an assignment might overwrite another assignment by a different thread in cases in which an abstract machine execution would not have encountered a data race. This includes implementations of data member assignment that overwrite adjacent members in separate memory locations. Reordering of atomic loads in cases in which the atomics in question may alias is also generally precluded, since this may violate the“visible sequence”coherence rules. —end note]
Change 29.3 [atomics.order] paragraph 3 as follows:
There shall be a single total order S on all memory_order_seq_cst operations, consistent with the “happens before” order and modification orders for all affected locations, such that each memory_order_seq_cst operation B that loads a value from an atomic object M observes one of the following values:
the result of the last modification A of M that precedes B in S, if it exists, or
if A exists, the result of some modification of M
in the visible sequence of side effects with respect to Bthat is not memory_order_seq_cst and that does not happen before A, orif A does not exist, the result of some modification of M
in the visible sequence of side effects with respect to Bthat is not memory_order_seq_cst.[Note:...
1673. Clarifying overload resolution for the second step of copy-initialization
Proposed resolution:
Change 13.3.3.1 [over.best.ics] paragraph 4 as follows:
However,
when considering the argument of a constructor or user-defined conversion function that is a candidate by 13.3.1.3 [over.match.ctor] when invoked for the copying/moving of the temporary in the second step of a class copy-initialization, by 13.3.1.7 [over.match.list] when passing the initializer list as a single argument or when the initializer list has exactly one element and a conversion to some class X or reference to (possibly cv-qualified) X is considered for the first parameter of a constructor of X, or by 13.3.1.4 [over.match.copy], 13.3.1.5 [over.match.conv], or 13.3.1.6 [over.match.ref] in all cases, only standard conversion sequences and ellipsis conversion sequences are considered.if the target is
the first parameter of a constructor or
the implicit object parameter of a user-defined conversion function
and the constructor or user-defined conversion function is a candidate by
13.3.1.3 [over.match.ctor], when the argument is the temporary in the second step of a class copy-initialization,
13.3.1.4 [over.match.copy], 13.3.1.5 [over.match.conv], or 13.3.1.6 [over.match.ref] (in all cases), or
the second phase of 13.3.1.7 [over.match.list] when the initializer list has exactly one element, and the target is the first parameter of a constructor of class X, and the conversion is to X or reference to (possibly cv-qualified) X,
user-defined conversion sequences are not considered. [Note: These rules prevent more than one user-defined conversion from being applied during overload resolution, thereby avoiding infinite recursion. —end note] [Example:
struct Y { Y(int); }; struct A { operator int(); }; Y y1 = A(); // error: A::operator int() is not a candidate struct X { }; struct B { operator X(); }; B b; X x({b}); // error: B::operator X() is not a candidate—end example]
1759. UTF-8 code units in plain char
Proposed resolution:
Change 2.14.5 [lex.string] paragraph 7 as follows:
A string literal that begins with u8, such as u8"asdf", is a UTF-8 string literaland is initialized with the given characters as encoded in UTF-8.
For a UTF-8 string literal, each successive element of the object representation (3.9 [basic.types[) has the value of the corresponding code unit of the UTF-8 encoding of the string.
Change 3.9.1 [basic.fundamental] paragraph 1 as follows:
...In any particular implementation, a plain char object can take on either the same values as a signed char or an unsigned char; which one is implementation-defined. For each value i of type unsigned char in the range 0 to 255 inclusive, there exists a value j of type char such that the result of an integral conversion (4.7 [conv.integral]) from i to char is j, and the result of an integral conversion from j to unsigned char is i.
1786. Effect of merging allocations on memory leakage
Proposed resolution:
1. Change 5.3.4 [expr.new] paragraph 10 as follows:
An implementation is allowed to omit a call to a replaceable global allocation function (18.6.1.1 [new.delete.single], 18.6.1.2 [new.delete.array]). When it does so, the storage is instead provided by the implementation or provided by extending the allocation of another new-expression. The implementation may extend the allocation of a new-expression e1 to provide storage for a new-expression e2 if the
lifetime of the object allocated by e1 strictly contains the lifetime of the object allocated by e2, e1 and e2 would invoke the same replaceable global allocation function, and, for a throwing allocation function, exceptions in e1 and e2 would be first caught in the same handler.following would be true were the allocation not extended:
the evaluation of e1 is sequenced before the evaluation of e2, and
e2 is evaluated whenever e1 obtains storage, and
both e1 and e2 invoke the same replaceable global allocation function, and
if the allocation function invoked by e1 and e2 is throwing, any exceptions thrown in the evaluation of either e1 or e2 would be first caught in the same handler, and
the pointer values produced by e1 and e2 are operands to evaluated delete-expressions, and
the evaluation of e2 is sequenced before the evaluation of the delete-expression whose operand is the pointer value produced by e1.
[Example:
void mergeable(int x) { // These heap allocations are safe for merging: std::unique_ptr<char[]> a{new (std::nothrow) char[8]}; std::unique_ptr<char[]> b{new (std::nothrow) char[8]}; std::unique_ptr<char[]> c{new (std::nothrow) char[x]}; g(a.get(), b.get(), c.get()); } void unmergeable(int x) { std::unique_ptr<char[]> a{new char[8]}; try { // Merging this allocation would change its catch handler. std::unique_ptr<char[]> b{new char[x]}; } catch (const std::bad_alloc& e) { std::cerr << "Allocation failed: " << e.what() << std::endl; throw; } }—end example]
Change 5.3.5 [expr.delete] paragraph 7 as follows:
If the value of the operand of the delete-expression is not a null pointer value, then:
If the allocation call for the new-expression for the object to be deleted was not omitted and the allocation was not extended (5.3.4 [expr.new]), the delete-expression shall call a deallocation function (3.7.4.2 [basic.std.dynamic.deallocation]). The value returned from the allocation call of the new-expression shall be passed as the first argument to the deallocation function.
Otherwise, if the allocation was extended or was provided by extending the allocation of another new-expression, and the delete-expression for every other pointer value produced by a new-expression that had storage provided by the extended new-expression has been evaluated, the delete-expression shall call a deallocation function. The value returned from the allocation call of the extended new-expression shall be passed as the first argument to the deallocation function.
Otherwise, the delete-expression will not call a deallocation function (3.7.4.2 [basic.std.dynamic.deallocation]).
Otherwise, it is unspecified whether the deallocation function will be called. [Note:...
1787. Uninitialized unsigned char values
Proposed resolution:
Change 3.3.2 [basic.scope.pdecl] paragraph 1 as follows:
The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below. [Example:
intunsigned char x = 12; {intunsigned char x = x; }Here the second x is initialized with its own (indeterminate) value. —end example]
Change 4.1 [conv.lval] paragraph 2 as follows:
When an lvalue-to-rvalue conversion occurs in an unevaluated operand or a subexpression thereof (Clause 5 [expr]) the value contained in the referenced object is not accessed. In all other cases, the result of the conversion is determined according to the following rules:
...
Otherwise, if T is a (possibly cv-qualified) unsigned character type (3.9.1 [basic.fundamental]), and the object to which the glvalue refers contains an indeterminate value (5.3.4 [expr.new], 8.5 [dcl.init], 12.6.2 [class.base.init]), and that object does not have automatic storage duration or the glvalue was the operand of a unary & operator or it was bound to a reference, the result is an unspecified value.57
Otherwise, if the object to which the glvalue refers contains an indeterminate value, the behavior is undefined.Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
Change 5.3.4 [expr.new] paragraph 17 as follows:
A new-expression that creates an object of type T initializes that object as follows:
If the new-initializer is omitted, the object is default-initialized (8.5 [dcl.init])
; if. [Note: If no initialization is performed, the object has an indeterminate value. —end note]Otherwise, the new-initializer is...
Change 8.5 [dcl.init] paragraph 12 as follows:
If no initializer is specified for an object, the object is default-initialized; if no initialization is performed,. When storage for an object with automatic or dynamic storage duration is obtained, the object hasindeterminate valuean indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.17 [expr.ass]). [Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2 [basic.start.init]. —end note] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
If an indeterminate value of unsigned narrow character type (3.9.1 [basic.fundamental]) is produced by the evaluation of:
the second or third operand of a conditional expression (5.16 [expr.cond]),
the right operand of a comma (5.18 [expr.comma]),
the operand of a cast or conversion to an unsigned narrow character type (4.7 [conv.integral], 5.2.3 [expr.type.conv], 5.2.9 [expr.static.cast], 5.4 [expr.cast]), or
a discarded-value expression (Clause 5 [expr]),
then the result of the operation is an indeterminate value.
If an indeterminate value of unsigned narrow character type (3.9.1 [basic.fundamental]) is produced by the evaluation of the right operand of a simple assignment operator (5.17 [expr.ass]) whose first operand is an lvalue of unsigned narrow character type, an indeterminate value replaces the value of the object referred to by the left operand.
If an indeterminate value of unsigned narrow character type (3.9.1 [basic.fundamental]) is produced by the evaluation of the initialization expression when initializing an object of unsigned narrow character type, that object is initialized to an indeterminate value.
[Example:
int f(bool b) { unsigned char c; unsigned char d = c; // OK, d has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if b is true }—end example]
Change 12.6.2 [class.base.init] paragraph 8 as follows:
...An attempt to initialize more than one non-static data member of a union renders the program ill-formed. [Note: After the call to a constructor for class X for an object with automatic or dynamic storage duration has completed, if the constructor was not invoked as part of value-initialization and a member of X is neither initialized nor given a value during execution of the compound-statement of the body of the constructor, the member has an indeterminate value. —end note] [Example:...