class module {}; module m1; // was variable declaration; now module-declaration module *m2; // variable declaration class import {}; import j1; // was variable declaration; now import-declaration ::import j2; // variable declaration— end example
template<typename> class import {}; import<int> f(); // ill-formed; previously well-formed ::import<int> g(); // OK— end example
namespace N { struct X {}; bool operator<=(X, X); template<bool(X, X)> struct Y {}; Y<operator<=> y; // ill-formed; previously well-formed }
const auto *u8s = u8"text"; // u8s previously deduced as const char*; now deduced as const char8_t* const char *ps = u8s; // ill-formed; previously well-formed auto u8c = u8'c'; // u8c previously deduced as char; now deduced as char8_t char *pc = &u8c; // ill-formed; previously well-formed std::string s = u8"text"; // ill-formed; previously well-formed void f(const char *s); f(u8"text"); // ill-formed; previously well-formed template<typename> struct ct; template<> struct ct<char> { using type = char; }; ct<decltype(u8'c')>::type x; // ill-formed; previously well-formed.
int f() { int a = 123; using T = int; a.~T(); return a; // undefined behavior; previously returned 123 }— end example
typedef struct { void f() {} // ill-formed; previously well-formed } S;
// Translation unit 1 int f(int a = 42); int g() { return f(); } // Translation unit 2 int f(int a = 76) { return a; } // ill-formed, no diagnostic required; previously well-formed int g(); int main() { return g(); } // used to return 42
struct A { // not an aggregate; previously an aggregate A() = delete; }; struct B { // not an aggregate; previously an aggregate B() = default; int i = 0; }; struct C { // not an aggregate; previously an aggregate C(C&&) = default; int a, b; }; A a{}; // ill-formed; previously well-formed B b = {1}; // ill-formed; previously well-formed auto* c = new C{2, 3}; // ill-formed; previously well-formed struct Y; struct X { operator Y(); }; struct Y { // not an aggregate; previously an aggregate Y(const Y&) = default; X x; }; Y y{X{}}; // copy constructor call; previously aggregate-initialization
bool y[] = { "bc" }; // ill-formed; previously well-formed
struct S { explicit (S)(const S&); // ill-formed; previously well-formed explicit (operator int)(); // ill-formed; previously well-formed explicit(true) (S)(int); // OK };
template<class T> struct A { A<T>(); // error: simple-template-id not allowed for constructor A(int); // OK, injected-class-name used ~A<T>(); // error: simple-template-id not allowed for destructor };
struct base { base(); base(base const &); private: base(base &&); }; struct derived : base {}; base f(base b) { throw b; // error: base(base &&) is private derived d; return d; // error: base(base &&) is private } struct S { S(const char *s) : m(s) { } S(const S&) = default; S(S&& other) : m(other.m) { other.m = nullptr; } const char * m; }; S consume(S&& s) { return s; } void g() { S s("text"); consume(static_cast<S&&>(s)); char c = *s.m; // undefined behavior; previously ok }
struct A { operator int() const; }; bool operator==(A, int); // #1 // #2 is built-in candidate: bool operator==(int, int); // #3 is built-in candidate: bool operator!=(int, int); int check(A x, A y) { return (x == y) + // ill-formed; previously well-formed (10 == x) + // calls #1, previously selected #2 (10 != x); // calls #1, previously selected #3 }
struct A {}; bool operator<(void (*fp)(), A); void f() {} int main() { A a; f < a; // ill-formed; previously well-formed (f) < a; // still well formed }
auto p = new char[100]; char q[100]; std::cin >> std::setw(20) >> p; // ill-formed; previously well-formed std::cin >> std::setw(20) >> q; // OK
std::cout << u8"text"; // previously called operator<<(const char*) and printed a string; // now ill-formed std::cout << u8'X'; // previously called operator<<(char) and printed a character; // now ill-formed
std::cout << u"text"; // previously formatted the string as a pointer value; // now ill-formed std::cout << u'X'; // previously formatted the character as an integer value; // now ill-formed
std::filesystem::path p; std::string s1 = p.u8string(); // ill-formed; previously well-formed std::string s2 = p.generic_u8string(); // ill-formed; previously well-formed