+2019-12-05 Marek Polacek <polacek@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+ * c-cppbuiltin.c (c_cpp_builtins): Adjust the value of __cpp_constexpr.
+
2019-12-05 Marek Polacek <polacek@redhat.com>
PR c++/92271 - make __is_same alias for __is_same_as.
cpp_define (pfile, "__cpp_fold_expressions=201603L");
cpp_define (pfile, "__cpp_nontype_template_args=201411L");
cpp_define (pfile, "__cpp_range_based_for=201603L");
- cpp_define (pfile, "__cpp_constexpr=201603L");
+ if (cxx_dialect <= cxx17)
+ cpp_define (pfile, "__cpp_constexpr=201603L");
cpp_define (pfile, "__cpp_if_constexpr=201606L");
cpp_define (pfile, "__cpp_capture_star_this=201603L");
cpp_define (pfile, "__cpp_inline_variables=201606L");
cpp_define (pfile, "__cpp_init_captures=201803L");
cpp_define (pfile, "__cpp_generic_lambdas=201707L");
cpp_define (pfile, "__cpp_designated_initializers=201707L");
+ cpp_define (pfile, "__cpp_constexpr=201907L");
cpp_define (pfile, "__cpp_constexpr_in_decltype=201711L");
cpp_define (pfile, "__cpp_conditional_explicit=201806L");
cpp_define (pfile, "__cpp_consteval=201811L");
+2019-12-05 Marek Polacek <polacek@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+ * class.c (trivial_default_constructor_is_constexpr): Return true in
+ C++20.
+ * constexpr.c (cx_check_missing_mem_inits): Allow missing field
+ initializers in C++20.
+ (cxx_eval_call_expression): Don't clear CONSTRUCTOR_NO_CLEARING for
+ constexpr constructors in C++20.
+ (reduced_constant_expression_p): Don't set FIELD for union and array
+ types. Skip empty class fields without initializers.
+ * decl.c (check_for_uninitialized_const_var): Permit trivial default
+ initialization in constexpr.
+ (next_initializable_field): Don't skip vptr fields.
+ * method.c (walk_field_subobs): Still consider a constructor that
+ doesn't initialize all the members constexpr.
+
2019-12-05 Marek Polacek <polacek@redhat.com>
PR c++/92271 - make __is_same alias for __is_same_as.
/* A defaulted trivial default constructor is constexpr
if there is nothing to initialize. */
gcc_assert (!TYPE_HAS_COMPLEX_DFLT (t));
- /* A class with a vptr doesn't have a trivial default ctor. */
- return is_really_empty_class (t, /*ignore_vptr*/true);
+ /* A class with a vptr doesn't have a trivial default ctor.
+ In C++20, a class can have transient uninitialized members, e.g.:
+
+ struct S { int i; constexpr S() = default; };
+
+ should work. */
+ return (cxx_dialect >= cxx2a
+ || is_really_empty_class (t, /*ignore_vptr*/true));
}
/* Returns true iff class T has a constexpr default constructor. */
static bool
cx_check_missing_mem_inits (tree ctype, tree body, bool complain)
{
+ /* We allow uninitialized bases/fields in C++20. */
+ if (cxx_dialect >= cxx2a)
+ return false;
+
unsigned nelts = 0;
if (body)
continue;
if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
- /* Recurse to check the anonummous aggregate member. */
+ /* Recurse to check the anonymous aggregate member. */
bad |= cx_check_missing_mem_inits
(TREE_TYPE (field), NULL_TREE, complain);
if (bad && !complain)
entry->result = result;
}
- /* The result of a constexpr function must be completely initialized. */
- if (TREE_CODE (result) == CONSTRUCTOR)
+ /* The result of a constexpr function must be completely initialized.
+
+ However, in C++20, a constexpr constructor doesn't necessarily have
+ to initialize all the fields, so we don't clear CONSTRUCTOR_NO_CLEARING
+ in order to detect reading an unitialized object in constexpr instead
+ of value-initializing it. (reduced_constant_expression_p is expected to
+ take care of clearing the flag.) */
+ if (TREE_CODE (result) == CONSTRUCTOR
+ && (cxx_dialect < cxx2a
+ || !DECL_CONSTRUCTOR_P (fun)))
clear_no_implicit_zero (result);
pop_cx_call_context ();
return result;
}
-/* FIXME speed this up, it's taking 16% of compile time on sieve testcase. */
+/* Return true if T is a valid constant initializer. If a CONSTRUCTOR
+ initializes all the members, the CONSTRUCTOR_NO_CLEARING flag will be
+ cleared.
+ FIXME speed this up, it's taking 16% of compile time on sieve testcase. */
bool
reduced_constant_expression_p (tree t)
if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
/* An initialized vector would have a VECTOR_CST. */
return false;
+ else if (cxx_dialect >= cxx2a
+ /* An ARRAY_TYPE doesn't have any TYPE_FIELDS. */
+ && (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
+ /* A union only initializes one member. */
+ || TREE_CODE (TREE_TYPE (t)) == UNION_TYPE))
+ field = NULL_TREE;
else
field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)));
}
return false;
if (field)
{
- if (idx != field)
- return false;
+ /* Empty class field may or may not have an initializer. */
+ for (; idx != field;
+ field = next_initializable_field (DECL_CHAIN (field)))
+ if (!is_really_empty_class (TREE_TYPE (field),
+ /*ignore_vptr*/false))
+ return false;
field = next_initializable_field (DECL_CHAIN (field));
}
}
- if (field)
- return false;
- else if (CONSTRUCTOR_NO_CLEARING (t))
+ /* There could be a non-empty field at the end. */
+ for (; field; field = next_initializable_field (DECL_CHAIN (field)))
+ if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false))
+ return false;
+ if (CONSTRUCTOR_NO_CLEARING (t))
/* All the fields are initialized. */
CONSTRUCTOR_NO_CLEARING (t) = false;
return true;
7.1.6 */
if (VAR_P (decl)
&& !TYPE_REF_P (type)
- && (constexpr_context_p
- || CP_TYPE_CONST_P (type) || var_in_constexpr_fn (decl))
+ && (CP_TYPE_CONST_P (type)
+ /* C++20 permits trivial default initialization in constexpr
+ context (P1331R2). */
+ || (cxx_dialect < cxx2a
+ && (constexpr_context_p
+ || var_in_constexpr_fn (decl))))
&& !DECL_NONTRIVIALLY_INITIALIZED_P (decl))
{
tree field = default_init_uninitialized_part (type);
bool show_notes = true;
- if (!constexpr_context_p)
+ if (!constexpr_context_p || cxx_dialect >= cxx2a)
{
if (CP_TYPE_CONST_P (type))
{
&& (TREE_CODE (field) != FIELD_DECL
|| DECL_UNNAMED_BIT_FIELD (field)
|| (DECL_ARTIFICIAL (field)
- && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field)))))
+ /* In C++17, don't skip base class fields. */
+ && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field))
+ /* Don't skip vptr fields. We might see them when we're
+ called from reduced_constant_expression_p. */
+ && !DECL_VIRTUAL_P (field))))
field = DECL_CHAIN (field);
return field;
if (bad && deleted_p)
*deleted_p = true;
- /* For an implicitly-defined default constructor to be constexpr,
- every member must have a user-provided default constructor or
- an explicit initializer. */
- if (constexpr_p && !CLASS_TYPE_P (mem_type)
+ /* Before C++20, for an implicitly-defined default constructor to
+ be constexpr, every member must have a user-provided default
+ constructor or an explicit initializer. */
+ if (constexpr_p
+ && cxx_dialect < cxx2a
+ && !CLASS_TYPE_P (mem_type)
&& TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE)
{
*constexpr_p = false;
+2019-12-05 Marek Polacek <polacek@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+ * g++.dg/cpp0x/constexpr-array6.C: Adjust dg-error.
+ * g++.dg/cpp0x/constexpr-ctor.C: Likewise.
+ * g++.dg/cpp0x/constexpr-diag3.C: Likewise.
+ * g++.dg/cpp0x/constexpr-diag4.C: Likewise.
+ * g++.dg/cpp0x/constexpr-ex3.C: Likewise.
+ * g++.dg/cpp0x/constexpr-template2.C: Likewise.
+ * g++.dg/cpp0x/constexpr-union2.C: Likewise.
+ * g++.dg/cpp0x/lambda/lambda-mangle.C: Rip out a piece of code ...
+ * g++.dg/cpp0x/lambda/lambda-mangle6.C: ... and put it here.
+ * g++.dg/cpp0x/pr79118.C: Adjust dg-error.
+ * g++.dg/cpp1y/constexpr-83921-3.C: Likewise.
+ * g++.dg/cpp1y/constexpr-neg1.C: Likewise.
+ * g++.dg/cpp1z/constexpr-lambda12.C: Likewise.
+ * g++.dg/cpp1z/feat-cxx1z.C: Use -std=c++17.
+ * g++.dg/cpp2a/constexpr-init1.C: New test.
+ * g++.dg/cpp2a/constexpr-init2.C: New test.
+ * g++.dg/cpp2a/constexpr-init3.C: New test.
+ * g++.dg/cpp2a/constexpr-init4.C: New test.
+ * g++.dg/cpp2a/constexpr-init5.C: New test.
+ * g++.dg/cpp2a/constexpr-init6.C: New test.
+ * g++.dg/cpp2a/constexpr-init7.C: New test.
+ * g++.dg/cpp2a/constexpr-init8.C: New test.
+ * g++.dg/cpp2a/constexpr-init9.C: New test.
+ * g++.dg/cpp2a/constexpr-init10.C: New test.
+ * g++.dg/cpp2a/constexpr-init11.C: New test.
+ * g++.dg/cpp2a/constexpr-init12.C: New test.
+ * g++.dg/cpp2a/constexpr-init13.C: New test.
+ * g++.dg/cpp2a/constexpr-init14.C: New test.
+ * g++.dg/cpp2a/constexpr-init15.C: New test.
+ * g++.dg/cpp2a/constexpr-try5.C: Adjust dg-error.
+ * g++.dg/cpp2a/feat-cxx2a.C: Test __cpp_constexpr.
+ * g++.dg/cpp2a/lambda-mangle.C: New test.
+ * g++.dg/debug/dwarf2/pr44641.C: Skip for c++2a.
+ * g++.dg/ext/stmtexpr21.C: Adjust dg-error.
+
2019-12-05 Marek Polacek <polacek@redhat.com>
PR c++/92271 - make __is_same alias for __is_same_as.
struct A
{
int i;
- constexpr A() {} // { dg-error "A::i" }
+ constexpr A() {} // { dg-error "A::i" "" { target c++17_down } }
};
struct B
A a;
};
-constexpr B b[] = { {} }; // { dg-error "A::A" }
+constexpr B b[] = { {} }; // { dg-error "A::A" "" { target c++17_down } }
+// { dg-error "is not a constant expression" "" { target c++2a } .-1 }
struct A
{
int i;
- constexpr A() { } // { dg-error "A::i" }
+ constexpr A() { } // { dg-error "A::i" "" { target c++17_down } }
};
{
int _M_i; // { dg-message "does not initialize" }
- constexpr Def() = default; // { dg-error "implicit declaration is not .constexpr." }
+ constexpr Def() = default; // { dg-error "implicit declaration is not .constexpr." "" { target c++17_down } }
};
constexpr Def defobj; // { dg-error "uninitialized" }
struct B1
{
A1 a1;
- constexpr B1() {} // { dg-error "B1::a1" }
+ constexpr B1() {} // { dg-error "B1::a1" "" { target c++17_down } }
};
struct A
{
int i;
- constexpr A(int _i) { i = _i; } // { dg-error "empty body|A::i" }
+ constexpr A(int _i) { i = _i; } // { dg-error "empty body|A::i" "" { target c++17_down } }
};
template <class T>
template <class T> struct A
{
T t;
- constexpr A() { } // { dg-error "::t" }
+ constexpr A() { } // { dg-error "::t" "" { target c++17_down } }
};
int main()
int x;
short y;
- constexpr bar() = default; // { dg-error "constexpr" }
+ constexpr bar() = default; // { dg-error "constexpr" "" { target c++17_down } }
};
[]{return 3;}());
};
-template<typename T> struct R {
- static int x;
-};
-// "int i;" makes the op() non-constexpr in C++17.
-template<typename T> int R<T>::x = []{int i; return 1;}();
-template int R<int>::x;
-// Type of lambda in intializer of R<int>::x: N1RIiE1xMUlvE_E
-// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv
-// { dg-final { scan-assembler "_ZNK1RIiE1xMUlvE_clEv" } }
-// { dg-final { scan-assembler "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" { target { ! { *-*-mingw* *-*-cygwin } } } } }
-
void bar()
{
// lambdas in non-vague linkage functions have internal linkage.
--- /dev/null
+// Test lambda mangling
+// { dg-do compile { target { c++11 && c++17_down } } }
+// { dg-require-weak "" }
+// { dg-options "-fno-inline" }
+
+template<typename T> struct R {
+ static int x;
+};
+// "int i;" makes the op() non-constexpr in C++17. In C++20, it does not.
+template<typename T> int R<T>::x = []{int i; return 1;}();
+template int R<int>::x;
+// Type of lambda in intializer of R<int>::x: N1RIiE1xMUlvE_E
+// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv
+// { dg-final { scan-assembler "_ZNK1RIiE1xMUlvE_clEv" } }
+// { dg-final { scan-assembler "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" { target { ! { *-*-mingw* *-*-cygwin } } } } }
constexpr One () : a(), b() {} // { dg-error "multiple" }
constexpr One (int) : a() {}
constexpr One (unsigned) : b () {}
- constexpr One (void *) {} // { dg-error "exactly one" }
+ constexpr One (void *) {} // { dg-error "exactly one" "" { target c++17_down } }
};
One a ();
};
constexpr Two () : a(), b() {}
- constexpr Two (int) : a() {} // { dg-error "b' must be initialized" }
- constexpr Two (unsigned) : b () {} // { dg-error "a' must be initialized" }
- constexpr Two (void *) {} // { dg-error "a' must be initialized" }
- // { dg-error "b' must be initialized" "" { target *-*-* } .-1 }
+ constexpr Two (int) : a() {} // { dg-error "b' must be initialized" "" { target c++17_down } }
+ constexpr Two (unsigned) : b () {} // { dg-error "a' must be initialized" "" { target c++17_down } }
+ constexpr Two (void *) {} // { dg-error "a' must be initialized" "" { target c++17_down } }
+ // { dg-error "b' must be initialized" "" { target c++17_down } .-1 }
};
Two e ();
// { dg-do compile { target c++14 } }
struct Foo { int m; };
-constexpr void test() { Foo f; } // { dg-error "uninitialized" }
+constexpr void test() { Foo f; } // { dg-error "uninitialized" "" { target c++17_down } }
goto foo; // { dg-error "goto" }
foo:
asm("foo"); // { dg-error "asm" "" { target c++17_down } }
- int k; // { dg-error "uninitialized" }
+ int k; // { dg-error "uninitialized" "" { target c++17_down } }
A a; // { dg-error "non-literal" }
return i;
}
void f(int i)
{
[i]() constexpr {
- int j; // { dg-error "uninitialized" }
+ int j; // { dg-error "uninitialized" "" { target c++17_down } }
j = i;
return j;
}();
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+// Test basic use.
+
+struct S {
+ int i;
+ constexpr S(bool b) {
+ if (b)
+ i = 42;
+ }
+};
+constexpr S s1(true);
+constexpr S s2(false); // { dg-error "not a constant expression" }
+
+constexpr int
+fn1 (int x)
+{
+ int a;
+ a = 5;
+ return x + a;
+}
+
+static_assert (fn1 (2) == 7);
+
+constexpr int
+fn2 (int x)
+{
+ const int a; // { dg-error "uninitialized .const a." }
+ constexpr int b; // { dg-error "uninitialized .const b." }
+ return x;
+}
+
+constexpr int
+fn3 (int x)
+{
+ int a; // { dg-message ".int a. is not const" }
+ return x + a; // { dg-error "the value of .a. is not usable in a constant expression" }
+}
+
+constexpr int a = fn3 (5); // { dg-message "in .constexpr. expansion of" }
+
+constexpr int
+fn4 ()
+{
+ struct S { int a = -5; int b; } s;
+ return s.a;
+}
+
+static_assert (fn4 () == -5);
+
+constexpr int
+fn5 ()
+{
+ struct S { int a = 9; int b; } s;
+ return s.b;
+}
+
+constexpr int b = fn5 (); // { dg-error "accessing uninitialized member" }
+// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 }
+
+constexpr int
+fn6 ()
+{
+ int a;
+ return 42;
+}
+
+static_assert (fn6 () == 42);
+
+constexpr int
+fn7 (bool b)
+{
+ int a; // { dg-message ".int a. is not const" }
+ if (b)
+ a = 42;
+ return a;
+}
+
+static_assert (fn7 (true) == 42);
+static_assert (fn7 (false) == 42); // { dg-error "non-constant condition|the value of .a. is not usable" }
+// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 }
+
+constexpr int
+fn8 (int n)
+{
+ int r;
+ switch (n)
+ {
+ case 1:
+ r = n;
+ return r;
+ case 42:
+ r = n;
+ return r;
+ }
+}
+
+static_assert (fn8 (1) == 1);
+static_assert (fn8 (42) == 42);
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+// In c++2a we don't emit a call to _ZN3FooI3ArgEC1Ev.
+
+struct Arg;
+struct Base {
+ int i;
+ virtual ~Base();
+};
+template <class> struct Foo : Base { };
+Foo<Arg> a;
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct S {
+ int i;
+ constexpr S(int) : i(10) {}
+};
+
+struct W {
+ constexpr W(int) : s(8), p() {}
+
+ S s;
+ int *p;
+};
+
+constexpr auto a = W(42);
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct S {
+ int uninit;
+ constexpr S(int) {}
+};
+
+struct W {
+ constexpr W(int) : s(8), p() {}
+
+ S s;
+ int *p;
+};
+
+constexpr auto a = W(42); // { dg-error "not a constant expression" }
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct E { };
+
+struct S {
+ E e;
+ constexpr S() {}
+};
+
+constexpr S s;
+constexpr S s2[4];
+
+struct W {
+ [[no_unique_address]] E e1, e2;
+ constexpr W() {}
+};
+
+constexpr W w;
+constexpr W w2[4];
+
+struct Y {
+ [[no_unique_address]] E e;
+ __extension__ char a[0];
+ constexpr Y() {}
+};
+
+constexpr Y y;
+constexpr Y y2[4];
+
+struct Z {
+ [[no_unique_address]] E e;
+ int i;
+ constexpr Z(int n) :i(n) { }
+};
+
+constexpr Z z(42);
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct E {
+ constexpr E() = default;
+ constexpr E(int) {}
+};
+
+struct W {
+ [[no_unique_address]] E e;
+ constexpr W(int) : e(8) {}
+};
+
+constexpr W w = W(42);
+
+struct S {
+ E e;
+ constexpr S() : e{} { }
+};
+
+constexpr S s;
+
+struct S2 {
+ [[no_unique_address]] E e;
+ constexpr S2() : e{} { }
+};
+
+constexpr S2 s2;
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct E {
+ constexpr E() = default;
+ constexpr E(int) {}
+};
+
+struct W {
+ [[no_unique_address]] E e;
+ int i;
+ constexpr W(int) : e(8), i(11) {}
+};
+
+constexpr W w = W(42);
+
+struct S {
+ E e;
+ int i;
+ constexpr S() : e{}, i(11) { }
+};
+
+constexpr S s;
+
+struct S2 {
+ [[no_unique_address]] E e;
+ int i;
+ constexpr S2() : e{}, i(11) { }
+};
+
+constexpr S2 s2;
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct A
+{
+ int i;
+ constexpr A() : i{} {}
+};
+
+struct B
+{
+ A a;
+};
+
+constexpr B b[] = { {} };
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct A
+{
+ int i;
+ constexpr A() {}
+};
+
+struct B
+{
+ A a;
+};
+
+// A::i not initialized.
+constexpr B b[] = { {} }; // { dg-error "is not a constant expression" }
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+// This bullet in [dcl.constexpr] is now gone:
+// - every non-static data member and base class sub-object shall be initialized
+
+struct A {
+ int i;
+ constexpr A(int _i) { i = _i; }
+};
+
+struct B {
+ int i;
+ constexpr B() { }
+};
+
+// Anonymous members.
+struct E {
+ int a;
+ union {
+ char b;
+ __extension__ struct {
+ double c;
+ long d;
+ };
+ union {
+ char e;
+ void *f;
+ };
+ };
+ __extension__ struct {
+ long long g;
+ __extension__ struct {
+ int h;
+ double i;
+ };
+ union {
+ char *j;
+ E *k;
+ };
+ };
+
+ // Completely initialized.
+ constexpr E(int(&)[1]) : a(), b(), g(), h(), i(), j() {}
+ constexpr E(int(&)[3]) : a(), e(), g(), h(), i(), k() {}
+ constexpr E(int(&)[7]) : a(), b(), g(), h(), i(), j() {}
+ constexpr E(int(&)[8]) : a(), f(), g(), h(), i(), k() {}
+ constexpr E(int(&)[9]) : a(), c(), d(), g(), h(), i(), k() {}
+
+ // Missing d, i, j/k union init.
+ constexpr E(int(&)[2]) : a(), c(), g(), h() {}
+
+ // Missing h, j/k union init.
+ constexpr E(int(&)[4]) : a(), c(), d(), g(), i() {}
+
+ // Missing b/c/d/e/f union init.
+ constexpr E(int(&)[5]) : a(), g(), h(), i(), k() {}
+
+ // Missing a, b/c/d/e/f union, g/h/i/j/k struct init.
+ constexpr E(int(&)[6]) {}
+};
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct S { int i; };
+
+constexpr void
+fn ()
+{
+ S s;
+
+ []() constexpr {
+ int i;
+ }();
+}
+
+constexpr int
+fn2 ()
+{
+ return __extension__ ({ int n; n; }); // { dg-error "not usable in a constant expression" }
+}
+
+constexpr int i = fn2 (); // { dg-message "in .constexpr. expansion of" }
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+/* We used to get the "constexpr constructor for union S::<unnamed union>
+ must initialize exactly one non-static data member" error, but not anymore
+ in C++20. */
+
+struct S {
+ union {
+ int i;
+ double d;
+ };
+ constexpr S() { }
+};
+
+union U {
+ int a;
+ constexpr U() { }
+};
+
+struct W {
+ union {
+ int a;
+ };
+ constexpr W() { }
+};
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct S {
+ int a = 1;
+ constexpr S() = default;
+};
+
+constexpr S s;
+
+union U {
+ int a = 1;
+ constexpr U() = default;
+};
+
+constexpr U u;
+
+struct S2 {
+ int a;
+ constexpr S2() = default;
+};
+
+constexpr S2 s2; // { dg-error "uninitialized .const s2." }
+
+union U2 {
+ int a;
+ constexpr U2() = default;
+};
+
+constexpr U2 u2; // { dg-error "uninitialized .const u2." }
+
+struct S3 {
+ // FIXME if it's anonymous union, we don't give the error below
+ union {
+ int a;
+ } u;
+ constexpr S3() = default;
+};
+
+constexpr S3 s3; // { dg-error "uninitialized .const s3." }
+
+struct S4 {
+ // FIXME if it's anonymous union, we don't give the error below
+ union {
+ int n;
+ } u;
+ constexpr S4() = default;
+};
+
+constexpr S4 s4; // { dg-error "uninitialized .const s4." }
+
+struct S5 {
+ union {
+ int n = 0;
+ };
+ // FIXME if it's anonymous union, we don't give the error below
+ union {
+ int m;
+ } u;
+ constexpr S5() = default;
+};
+
+constexpr S5 s5; // { dg-error "uninitialized .const s5.|not a constant expression" }
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct S {
+ constexpr S(int) {}
+};
+
+struct W {
+ constexpr W(int) : s(8), p() {}
+
+ S s;
+ int *p;
+};
+
+constexpr auto a = W(42);
--- /dev/null
+// PR c++/91353 - P1331R2: Allow trivial default init in constexpr contexts.
+// { dg-do compile { target c++2a } }
+
+struct S {
+ constexpr S(int) {}
+};
+
+struct W {
+ constexpr W(int (&)[8]) : W(8) { }
+ constexpr W(int) : s(8), p() {}
+
+ S s;
+ int *p;
+};
+
+int arr[8];
+constexpr auto a = W(arr);
constexpr int foo ()
try { // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
- int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" }
+ int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } }
static double b = 1.0;// { dg-error "'b' declared 'static' in 'constexpr' function" }
goto l; // { dg-error "'goto' in 'constexpr' function" }
l:;
return 0;
} catch (...) {
- long int c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" }
+ long int c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" "" { target c++17_down } }
static float d = 2.0f;// { dg-error "'d' declared 'static' in 'constexpr' function" }
goto l2; // { dg-error "'goto' in 'constexpr' function" }
l2:;
constexpr int bar ()
{
- int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" }
+ int a; // { dg-error "uninitialized variable 'a' in 'constexpr' function" "" { target c++17_down } }
static long double b = 3.0;// { dg-error "'b' declared 'static' in 'constexpr' function" }
goto l; // { dg-error "'goto' in 'constexpr' function" }
l:;
try { // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
- short c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" }
+ short c; // { dg-error "uninitialized variable 'c' in 'constexpr' function" "" { target c++17_down } }
static float d; // { dg-error "'d' declared 'static' in 'constexpr' function" }
- // { dg-error "uninitialized variable 'd' in 'constexpr' function" "" { target *-*-* } .-1 }
+ // { dg-error "uninitialized variable 'd' in 'constexpr' function" "" { target c++17_down } .-1 }
goto l2; // { dg-error "'goto' in 'constexpr' function" }
l2:;
return 0;
} catch (int) {
- char e; // { dg-error "uninitialized variable 'e' in 'constexpr' function" }
+ char e; // { dg-error "uninitialized variable 'e' in 'constexpr' function" "" { target c++17_down } }
static int f = 5; // { dg-error "'f' declared 'static' in 'constexpr' function" }
goto l3; // { dg-error "'goto' in 'constexpr' function" }
l3:;
#ifndef __cpp_constexpr
# error "__cpp_constexpr"
-#elif __cpp_constexpr != 201603
-# error "__cpp_constexpr != 201603"
+#elif __cpp_constexpr != 201907
+# error "__cpp_constexpr != 201907"
#endif
#ifndef __cpp_decltype_auto
--- /dev/null
+// Test lambda mangling
+// { dg-do compile { target c++2a } }
+// { dg-require-weak "" }
+// { dg-options "-fno-inline" }
+
+template<typename T> struct R {
+ static int x;
+};
+// "int i;" makes the op() non-constexpr in C++17. In C++20, it does not.
+template<typename T> int R<T>::x = []{int i; return 1;}();
+template int R<int>::x;
+// Type of lambda in intializer of R<int>::x: N1RIiE1xMUlvE_E
+// Corresponding operator(): _ZNK1RIiE1xMUlvE_clEv
+// { dg-final { scan-assembler-not "_ZNK1RIiE1xMUlvE_clEv" } }
+// { dg-final { scan-assembler-not "weak\[^\n\r\]*_?_ZNK1RIiE1xMUlvE_clEv" } }
// Origin: PR 44641
-// { dg-do compile }
+// { dg-do compile { target c++17_down } }
// { dg-options "-gdwarf-2 -O0 -dA" }
template <class A> struct MisplacedDbg;
static MisplacedDbg<Arg> static_var1;
static MisplacedDbg<Arg*> static_var2;
static MisplacedDbg<Full> static_var3;
+
+// This test is skipped in C++20 because we consider the default constructor
+// MisplacedDbg() constexpr despite the uninitialized member "int i;". So
+// the calls to
+// MisplacedDbg<Arg>::MisplacedDbg()
+// MisplacedDbg<Full>::MisplacedDbg()
+// MisplacedDbg<Arg*>::MisplacedDbg()
+// are elided. (This comment is here not to mess up the line numbers.)
const test* setup()
{
static constexpr test atest =
- { ({ int inner; (const int*)(0); }) }; // { dg-error "uninitialized" }
+ { ({ int inner; (const int*)(0); }) }; // { dg-error "uninitialized" "" { target c++17_down } }
return &atest;
}