[diff.cpp20]

# Annex C (informative) Compatibility [[diff]](./#diff)

## C.2 C++ and ISO C++ 2020 [diff.cpp20]

### [C.2.1](#general) General [[diff.cpp20.general]](diff.cpp20.general)

[1](#general-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L461)

Subclause [diff.cpp20] lists the differences between C++ and
ISO C++ 2020,
in addition to those listed above,
by the chapters of this document[.](#general-1.sentence-1)

### [C.2.2](#lex) [[lex]](lex "5 Lexical conventions"): lexical conventions [[diff.cpp20.lex]](diff.cpp20.lex)

[1](#lex-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L470)

**Affected subclause:** [[lex.name]](lex.name)  


**Change:** Previously valid identifiers containing characters
not present in UAX #44 properties XID_Start or XID_Continue, or
not in Normalization Form C, are now rejected[.](#lex-1.sentence-1)

  


**Rationale:** Prevent confusing characters in identifiers[.](#lex-1.sentence-2)

Requiring normalization of names ensures consistent linker behavior[.](#lex-1.sentence-3)

  


**Effect on original feature:** Some identifiers are no longer well-formed[.](#lex-1.sentence-4)

[2](#lex-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L483)

**Affected subclause:** [[lex.string]](lex.string)  


**Change:** Concatenated [*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]")*s* can no longer have
conflicting [*encoding-prefix*](lex.ccon#nt:encoding-prefix "5.13.3 Character literals [lex.ccon]")es[.](#lex-2.sentence-1)

  


**Rationale:** Removal of unimplemented conditionally-supported feature[.](#lex-2.sentence-2)

  


**Effect on original feature:** Concatenation of [*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]")*s* with different [*encoding-prefix*](lex.ccon#nt:encoding-prefix "5.13.3 Character literals [lex.ccon]")es
is now ill-formed[.](#lex-2.sentence-3)

[*Example [1](#lex-example-1)*: auto c = L"a" U"b"; // was conditionally-supported; now ill-formed â *end example*]

### [C.2.3](#expr) [[expr]](expr "7 Expressions"): expressions [[diff.cpp20.expr]](diff.cpp20.expr)

[1](#expr-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L501)

**Affected subclause:** [[expr.prim.id.unqual]](expr.prim.id.unqual)  


**Change:** Change move-eligible [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")*s* from lvalues to xvalues[.](#expr-1.sentence-1)

  


**Rationale:** Simplify the rules for implicit move[.](#expr-1.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code that relies on a returned [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")'s
being an lvalue may change behavior or fail to compile[.](#expr-1.sentence-3)

[*Example [1](#expr-example-1)*: decltype(auto) f(int&& x) { return (x); } // returns int&&; previously returned int&int& g(int&& x) { return x; } // ill-formed; previously well-formed â *end example*]

[2](#expr-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L516)

**Affected subclause:** [[expr.sub]](expr.sub)  


**Change:** Change the meaning of comma in subscript expressions[.](#expr-2.sentence-1)

  


**Rationale:** Enable repurposing a deprecated syntax to support multidimensional indexing[.](#expr-2.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code that uses a comma expression within a
subscript expression may fail to compile[.](#expr-2.sentence-3)

[*Example [2](#expr-example-2)*: arr[1, 2] // was equivalent to arr[(1, 2)],// now equivalent to arr.operator[](1, 2) or ill-formed â *end example*]

### [C.2.4](#stmt) [[stmt]](stmt "8 Statements"): statements [[diff.cpp20.stmt]](diff.cpp20.stmt)

[1](#stmt-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L533)

**Affected subclause:** [[stmt.ranged]](stmt.ranged)  


**Change:** The lifetime of temporary objects in the [*for-range-initializer*](stmt.pre#nt:for-range-initializer "8.1 Preamble [stmt.pre]") is extended until the end of the loop ([[class.temporary]](class.temporary "6.8.7 Temporary objects"))[.](#stmt-1.sentence-1)

  


**Rationale:** Improve usability of the range-based for statement[.](#stmt-1.sentence-2)

  


**Effect on original feature:** Destructors of some temporary objects are invoked later[.](#stmt-1.sentence-3)

[*Example [1](#stmt-example-1)*: void f() { std::vector<int> v = { 42, 17, 13 };
 std::mutex m; for (int x :static_cast<void>(std::lock_guard<std::mutex>(m)), v) { // lock released in C++ 2020 std::lock_guard<std::mutex> guard(m); // OK in C++ 2020, now deadlocks}} â *end example*]

### [C.2.5](#dcl) [[dcl]](dcl "9 Declarations"): declarations [[diff.cpp20.dcl]](diff.cpp20.dcl)

[1](#dcl-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L557)

**Affected subclause:** [[dcl.init.string]](dcl.init.string)  


**Change:** UTF-8 string literals may initialize arrays of char orunsigned char[.](#dcl-1.sentence-1)

  


**Rationale:** Compatibility with previously written code that conformed to previous versions of this document[.](#dcl-1.sentence-2)

  


**Effect on original feature:** Arrays of char or unsigned char may now be initialized with a UTF-8 string literal[.](#dcl-1.sentence-3)

This can affect initialization that includes arrays
that are directly initialized within class types, typically aggregates[.](#dcl-1.sentence-4)

[*Example [1](#dcl-example-1)*: struct A {char8_t s[10];};struct B {char s[10];};

void f(A);void f(B);

int main() { f({u8""}); // ambiguous} â *end example*]

### [C.2.6](#temp) [[temp]](temp "13 Templates"): templates [[diff.cpp20.temp]](diff.cpp20.temp)

[1](#temp-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L588)

**Affected subclause:** [[temp.deduct.type]](temp.deduct.type)  


**Change:** Deducing template arguments from exception specifications[.](#temp-1.sentence-1)

  


**Rationale:** Facilitate generic handling of throwing and non-throwing functions[.](#temp-1.sentence-2)

  


**Effect on original feature:** Valid ISO C++ 2020 code may be ill-formed in this revision of C++[.](#temp-1.sentence-3)

[*Example [1](#temp-example-1)*: template<bool> struct A { };template<bool B> void f(void (*)(A<B>) noexcept(B));void g(A<false>) noexcept;void h() { f(g); // ill-formed; previously well-formed} â *end example*]

### [C.2.7](#library) [[library]](library "16 Library introduction"): library introduction [[diff.cpp20.library]](diff.cpp20.library)

[1](#library-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L608)

**Affected subclause:** [[headers]](headers)  


**Change:** New headers[.](#library-1.sentence-1)

  


**Rationale:** New functionality[.](#library-1.sentence-2)

  


**Effect on original feature:** The following C++ headers are new:[<expected>](expected.syn#header:%3cexpected%3e "22.8.2 Header <expected> synopsis [expected.syn]"),[<flat_map>](flat.map.syn#header:%3cflat_map%3e "23.6.7 Header <flat_­map> synopsis [flat.map.syn]"),[<flat_set>](flat.set.syn#header:%3cflat_set%3e "23.6.10 Header <flat_­set> synopsis [flat.set.syn]"),[<generator>](generator.syn#header:%3cgenerator%3e "25.8.2 Header <generator> synopsis [generator.syn]"),[<mdspan>](mdspan.syn#header:%3cmdspan%3e "23.7.3.2 Header <mdspan> synopsis [mdspan.syn]"),[<print>](print.syn#header:%3cprint%3e "31.7.4 Header <print> synopsis [print.syn]"),[<spanstream>](span.streams.overview#header:%3cspanstream%3e "31.9.1 Overview [span.streams.overview]"),[<stacktrace>](stacktrace.syn#header:%3cstacktrace%3e "19.6.2 Header <stacktrace> synopsis [stacktrace.syn]"),[<stdatomic.h>](stdatomic.h.syn#header:%3cstdatomic.h%3e "32.5.12 C compatibility [stdatomic.h.syn]"), and[<stdfloat>](stdfloat.syn#header:%3cstdfloat%3e "17.4.2 Header <stdfloat> synopsis [stdfloat.syn]")[.](#library-1.sentence-3)

Valid C++ 2020 code that #includes headers with these names may be
invalid in this revision of C++[.](#library-1.sentence-4)

### [C.2.8](#concepts) [[concepts]](concepts "18 Concepts library"): concepts library [[diff.cpp20.concepts]](diff.cpp20.concepts)

[1](#concepts-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L630)

**Affected subclauses:** [[cmp.concept]](cmp.concept), [[concept.equalitycomparable]](concept.equalitycomparable), and [[concept.totallyordered]](concept.totallyordered)  


**Change:** Replace common_reference_with in three_way_comparable_with,equality_comparable_with, and totally_ordered_with with an exposition-only concept[.](#concepts-1.sentence-1)

  


**Rationale:** Allow uncopyable, but movable, types to model these concepts[.](#concepts-1.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code relying on subsumption
with common_reference_with may fail to compile in this revision of C++[.](#concepts-1.sentence-3)

[*Example [1](#concepts-example-1)*: template<class T, class U>requires [equality_comparable_with](concept.equalitycomparable#concept:equality_comparable_with "18.5.4 Concept equality_­comparable [concept.equalitycomparable]")<T, U>bool attempted_equals(const T&, const U& u); // previously selected overloadtemplate<class T, class U>requires [common_reference_with](concept.commonref#concept:common_reference_with "18.4.5 Concept common_­reference_­with [concept.commonref]")<const remove_reference_t<T>&, const remove_reference_t<U>&>bool attempted_equals(const T& t, const U& u); // ambiguous overload; previously// rejected by partial orderingbool test(shared_ptr<int> p) {return attempted_equals(p, nullptr); // ill-formed; previously well-formed} â *end example*]

### [C.2.9](#memory) [[mem]](mem "20 Memory management library"): memory management library [[diff.cpp20.memory]](diff.cpp20.memory)

[1](#memory-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L659)

**Affected subclause:** [[allocator.traits.general]](allocator.traits.general)  


**Change:** Forbid partial and explicit program-defined specializations
of allocator_traits[.](#memory-1.sentence-1)

  


**Rationale:** Allow addition of allocate_at_least to allocator_traits,
and potentially other members in the future[.](#memory-1.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code
that partially or explicitly specializes allocator_traits is ill-formed with no diagnostic required in this revision of C++[.](#memory-1.sentence-3)

### [C.2.10](#utilities) [[utilities]](utilities "22 General utilities library"): general utilities library [[diff.cpp20.utilities]](diff.cpp20.utilities)

[1](#utilities-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L673)

**Affected subclause:** [[format]](format)  


**Change:** Signature changes: format, format_to, vformat_to,format_to_n, formatted_size[.](#utilities-1.sentence-1)

Removal of format_args_t[.](#utilities-1.sentence-2)

  


**Rationale:** Improve safety via compile-time format string checks,
avoid unnecessary template instantiations[.](#utilities-1.sentence-3)

  


**Effect on original feature:** Valid C++ 2020 code that
contained errors in format strings or
relied on previous format string signatures orformat_args_t may become ill-formed[.](#utilities-1.sentence-4)

[*Example [1](#utilities-example-1)*: auto s = std::format("{:d}", "I am not a number"); // ill-formed,// previously threw format_error â *end example*]

[2](#utilities-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L693)

**Affected subclause:** [[format]](format)  


**Change:** Signature changes: format, format_to, format_to_n,formatted_size[.](#utilities-2.sentence-1)

  


**Rationale:** Enable formatting of views
that do not support iteration when const-qualified and
that are not copyable[.](#utilities-2.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code that passes bit-fields to formatting functions
may become ill-formed[.](#utilities-2.sentence-3)

[*Example [2](#utilities-example-2)*: struct tiny {int bit: 1;};

auto t = tiny();
std::format("{}", t.bit); // ill-formed, previously returned "0" â *end example*]

[3](#utilities-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L715)

**Affected subclause:** [[format.string.std]](format.string.std)  


**Change:** Restrict types of formatting arguments
used as *width* or *precision* in
a *std-format-spec*[.](#utilities-3.sentence-1)

  


**Rationale:** Disallow types that do not have useful or portable semantics as
a formatting width or precision[.](#utilities-3.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code that passes a boolean or character type as*arg-id* becomes invalid[.](#utilities-3.sentence-3)

[*Example [3](#utilities-example-3)*: std::format("{:*^{}}", "", true); // ill-formed, previously returned "*" std::format("{:*^{}}", "", '1'); // ill-formed, previously returned an// implementation-defined number of '*' characters â *end example*]

[4](#utilities-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L734)

**Affected subclause:** [[format.formatter.spec]](format.formatter.spec)  


**Change:** Removed the formatter specialization:template<size_t N> struct formatter<const charT[N], charT>;  

**Rationale:** The specialization is inconsistent with the design of formatter,
which is intended to be instantiated only with cv-unqualified object types[.](#utilities-4.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code that instantiated the removed specialization
can become ill-formed[.](#utilities-4.sentence-3)

### [C.2.11](#strings) [[strings]](strings "27 Strings library"): strings library [[diff.cpp20.strings]](diff.cpp20.strings)

[1](#strings-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L749)

**Affected subclause:** [[string.classes]](string.classes)  


**Change:** Additional rvalue overload for the substr member function and
the corresponding constructor[.](#strings-1.sentence-1)

  


**Rationale:** Improve efficiency of operations on rvalues[.](#strings-1.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code that created a substring
by calling substr (or the corresponding constructor)
on an xvalue expression with type S that is a specialization of basic_string may change meaning in this revision of C++[.](#strings-1.sentence-3)

[*Example [1](#strings-example-1)*: std::string s1 = "some long string that forces allocation", s2 = s1;
std::move(s1).substr(10, 5);
assert(s1 == s2); // unspecified, previously guaranteed to be true std::string s3(std::move(s2), 10, 5);
assert(s1 == s2); // unspecified, previously guaranteed to be true â *end example*]

### [C.2.12](#containers) [[containers]](containers "23 Containers library"): containers library [[diff.cpp20.containers]](diff.cpp20.containers)

[1](#containers-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L773)

**Affected subclauses:** [[associative.reqmts]](associative.reqmts) and [[unord.req]](unord.req)  


**Change:** Heterogeneous extract and erase overloads
for associative containers[.](#containers-1.sentence-1)

  


**Rationale:** Improve efficiency of erasing elements from associative containers[.](#containers-1.sentence-2)

  


**Effect on original feature:** Valid C++ 2020 code may fail to compile in this revision of C++[.](#containers-1.sentence-3)

[*Example [1](#containers-example-1)*: struct B {auto operator<=>(const B&) const = default;};

struct D : private B {void f(std::set<B, std::less<>>& s) { s.erase(*this); // ill-formed; previously well-formed}}; â *end example*]

### [C.2.13](#thread) [[thread]](thread "32 Concurrency support library"): concurrency support library [[diff.cpp20.thread]](diff.cpp20.thread)

[1](#thread-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L797)

**Affected subclause:** [[thread.barrier]](thread.barrier)  


**Change:** In this revision of C++,
it is implementation-defined whether a barrier's phase completion step runs
if no thread calls wait[.](#thread-1.sentence-1)

Previously the phase completion step was guaranteed to run on the last thread that calls arrive or arrive_and_drop during the phase[.](#thread-1.sentence-2)

In this revision of C++,
it can run on any of the threads that arrived or waited at the barrier
during the phase[.](#thread-1.sentence-3)

  


**Rationale:** Correct contradictory wording and
improve implementation flexibility for performance[.](#thread-1.sentence-4)

  


**Effect on original feature:** Valid C++ 2020 code using a barrier might have
different semantics in this revision of C++
if it depends on a completion function's side effects occurring exactly once,
on a specific thread running the phase completion step, or
on a completion function's side effects occurring
without wait having been called[.](#thread-1.sentence-5)

[*Example [1](#thread-example-1)*: auto b0 = std::barrier(1);
b0.arrive();
b0.arrive(); // implementation-defined; previously well-definedint data = 0;auto b1 = std::barrier(1, [&] { data++; });
b1.arrive();
assert(data == 1); // implementation-defined; previously well-defined b1.arrive(); // implementation-defined; previously well-defined â *end example*]
