On 12/1/19 8:09 PM, Marek Polacek wrote:
On Thu, Nov 28, 2019 at 11:29:20PM -0500, Jason Merrill wrote:
Sounds like reduced_constant_expression_p needs to deal better with empty
bases.
This got a bit complicated because it also needs to handle unions and
now we also need to heed vptr. But the following seems to work.
(I'll skip the story about a bogus error I hit when building cmcstl2 and
the need to debug a ~90,000 LOC test, because creduce got stuck reducing
it.)
Bootstrapped/regtested on x86_64-linux, built Boost and cmcstl2.
Ok?
2019-12-01 Marek Polacek <pola...@redhat.com>
Jakub Jelinek <ja...@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.
* 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. Adjust calls to next_initializable_field.
* cp-tree.h (next_initializable_field): Adjust declaration.
* decl.c (check_for_uninitialized_const_var): Permit trivial default
initialization in constexpr.
(next_initializable_field): Add a bool parameter. Use it.
* method.c (walk_field_subobs): Still consider a constructor that
doesn't initialize all the members constexpr.
* 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-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.
diff --git gcc/c-family/c-cppbuiltin.c gcc/c-family/c-cppbuiltin.c
index 6491545bc3b..680087cd254 100644
--- gcc/c-family/c-cppbuiltin.c
+++ gcc/c-family/c-cppbuiltin.c
@@ -975,7 +975,8 @@ c_cpp_builtins (cpp_reader *pfile)
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");
@@ -997,6 +998,7 @@ c_cpp_builtins (cpp_reader *pfile)
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");
diff --git gcc/cp/class.c gcc/cp/class.c
index f36f75fa0db..d8bb44990b7 100644
--- gcc/cp/class.c
+++ gcc/cp/class.c
@@ -5288,8 +5288,14 @@ trivial_default_constructor_is_constexpr (tree t)
/* 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. */
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index ee3ccb9691c..fa8dde9e22b 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -779,7 +779,9 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool
complain)
if (TREE_CODE (ctype) == UNION_TYPE)
{
- if (nelts == 0 && next_initializable_field (field))
+ if (cxx_dialect < cxx2a
+ && nelts == 0
+ && next_initializable_field (field))
Do we want cx_check_missing_mem_inits to do anything in C++20? Or can
we return immediately at the beginning?
{
if (complain)
error ("%<constexpr%> constructor for union %qT must "
@@ -2153,15 +2157,27 @@ cxx_eval_call_expression (const constexpr_ctx *ctx,
tree t,
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)
+ || !DECL_DECLARED_CONSTEXPR_P (fun)))
How can we get here for a non-constexpr function?
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)
@@ -2183,8 +2199,17 @@ 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)));
+ /* In C++20, skip fields that don't actually need initializing,
+ like empty bases. */
+ field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)),
+ cxx_dialect >= cxx2a);
}
else
field = NULL_TREE;
@@ -2198,7 +2223,8 @@ reduced_constant_expression_p (tree t)
{
if (idx != field)
return false;
- field = next_initializable_field (DECL_CHAIN (field));
+ field = next_initializable_field (DECL_CHAIN (field),
+ cxx_dialect >= cxx2a);
}
}
if (field)
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 7e810b8ee7b..35f3352bdff 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -6541,7 +6541,7 @@ extern bool is_direct_enum_init (tree,
tree);
extern void initialize_artificial_var (tree, vec<constructor_elt,
va_gc> *);
extern tree check_var_type (tree, tree, location_t);
extern tree reshape_init (tree, tree, tsubst_flags_t);
-extern tree next_initializable_field (tree);
+extern tree next_initializable_field (tree, bool = false);
extern tree fndecl_declared_return_type (tree);
extern bool undeduced_auto_decl (tree);
extern bool require_deduced_type (tree, tsubst_flags_t =
tf_warning_or_error);
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 81d73433547..9feba7d5b54 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
+next_initializable_field (tree field, bool skip_empty /*=false*/)
{
while (field
&& (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))
+ /* In C++20, don't skip vptr fields. */
+ && !(cxx_dialect >= cxx2a && DECL_VIRTUAL_P (field)))
I don't think this needs to be specific to C++20; in all language
revisions a vptr makes a class non-aggregate, so we'd only get here for
a use like that in reduced_constant_expression_p.
+ || (skip_empty
+ && is_really_empty_class (TREE_TYPE (field),
This should probably check DECL_SIZE (field) == size_zero_node instead,
since that will properly distinguish between overlapping and
non-overlapping data members of empty class type. And please test how
this works with data members of empty class type both with and without
[[no_unique_address]].
Jason