c++: check constexpr constructor body

The implicit constexpr patch revealed that our checks for constexpr
constructors that could possibly produce a constant value (which
otherwise are IFNDR) was failing to look at most of the function body.
Fixing that required some library tweaks.

gcc/cp/ChangeLog:

	* constexpr.c (maybe_save_constexpr_fundef): Also check whether the
	body of a constructor is potentially constant.

libstdc++-v3/ChangeLog:

	* src/c++17/memory_resource.cc: Add missing constexpr.
	* include/experimental/internet: Only mark copy constructor
	as constexpr with __cpp_constexpr_dynamic_alloc.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1y/constexpr-89285-2.C: Expect error.
	* g++.dg/cpp1y/constexpr-89285.C: Adjust error.
This commit is contained in:
Jason Merrill 2021-11-13 16:59:31 -05:00
parent daa9c6b015
commit 37326651b4
5 changed files with 25 additions and 10 deletions

View file

@ -870,7 +870,9 @@ maybe_save_constexpr_fundef (tree fun)
|| (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun)))
return;
if (!is_valid_constexpr_fn (fun, !DECL_GENERATED_P (fun)))
bool complain = !DECL_GENERATED_P (fun);
if (!is_valid_constexpr_fn (fun, complain))
return;
tree massaged = massage_constexpr_body (fun, DECL_SAVED_TREE (fun));
@ -883,15 +885,26 @@ maybe_save_constexpr_fundef (tree fun)
}
bool potential = potential_rvalue_constant_expression (massaged);
if (!potential && !DECL_GENERATED_P (fun))
if (!potential && complain)
require_potential_rvalue_constant_expression (massaged);
if (DECL_CONSTRUCTOR_P (fun)
&& cx_check_missing_mem_inits (DECL_CONTEXT (fun),
massaged, !DECL_GENERATED_P (fun)))
potential = false;
if (DECL_CONSTRUCTOR_P (fun) && potential)
{
if (cx_check_missing_mem_inits (DECL_CONTEXT (fun),
massaged, complain))
potential = false;
else if (cxx_dialect > cxx11)
{
/* What we got from massage_constexpr_body is pretty much just the
ctor-initializer, also check the body. */
massaged = DECL_SAVED_TREE (fun);
potential = potential_rvalue_constant_expression (massaged);
if (!potential && complain)
require_potential_rvalue_constant_expression (massaged);
}
}
if (!potential && !DECL_GENERATED_P (fun))
if (!potential && complain)
return;
constexpr_fundef entry = {fun, NULL_TREE, NULL_TREE, NULL_TREE};

View file

@ -10,7 +10,7 @@ struct B {
int *c = &x->a;
while (*c)
c = reinterpret_cast<int *>((reinterpret_cast<char *>(c) + *c));
*c = reinterpret_cast<char *>(this) - reinterpret_cast<char *>(c);
*c = reinterpret_cast<char *>(this) - reinterpret_cast<char *>(c); // { dg-error "reinterpret_cast" }
}
};
struct C : A {

View file

@ -17,4 +17,4 @@ struct C : A {
B bar {this};
};
constexpr C foo {}; // { dg-message "expansion of" }
constexpr C foo {}; // { dg-message "" }

View file

@ -460,7 +460,9 @@ namespace ip
// constructors:
constexpr address() noexcept : _M_v4(), _M_is_v4(true) { }
#if __cpp_constexpr_dynamic_alloc
constexpr
#endif
address(const address& __a) noexcept : _M_uninit(), _M_is_v4(__a._M_is_v4)
{
if (_M_is_v4)

View file

@ -603,7 +603,7 @@ namespace pmr
void* pointer = nullptr;
aligned_size<min> _M_size;
size_t size() const noexcept
constexpr size_t size() const noexcept
{
if (_M_size.value == size_t(-1)) [[unlikely]]
return size_t(-1);