Skip to content

Commit

Permalink
c++: Improve contracts support in modules [PR108205]
Browse files Browse the repository at this point in the history
Modules makes some assumptions about types that currently aren't
fulfilled by the types created in contracts logic.  This patch ensures
that exporting inline functions using contracts works again with
modules.

	PR c++/108205

gcc/cp/ChangeLog:

	* contracts.cc (get_pseudo_contract_violation_type): Give names
	to generated FIELD_DECLs.
	(declare_handle_contract_violation): Mark contract_violation
	type as external linkage.
	(build_contract_handler_call): Ensure any builtin declarations
	created here aren't treated as attached to the current module.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/contracts-5_a.C: New test.
	* g++.dg/modules/contracts-5_b.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
  • Loading branch information
wreien committed Feb 4, 2025
1 parent 736e8ee commit d3627c7
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 9 deletions.
27 changes: 18 additions & 9 deletions gcc/cp/contracts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1633,19 +1633,22 @@ get_pseudo_contract_violation_type ()
signed char _M_continue;
If this changes, also update the initializer in
build_contract_violation. */
const tree types[] = { const_string_type_node,
const_string_type_node,
const_string_type_node,
const_string_type_node,
const_string_type_node,
uint_least32_type_node,
signed_char_type_node };
struct field_info { tree type; const char* name; };
const field_info info[] = {
{ const_string_type_node, "_M_file" },
{ const_string_type_node, "_M_function" },
{ const_string_type_node, "_M_comment" },
{ const_string_type_node, "_M_level" },
{ const_string_type_node, "_M_role" },
{ uint_least32_type_node, "_M_line" },
{ signed_char_type_node, "_M_continue" }
};
tree fields = NULL_TREE;
for (tree type : types)
for (const field_info& i : info)
{
/* finish_builtin_struct wants fieldss chained in reverse. */
tree next = build_decl (BUILTINS_LOCATION, FIELD_DECL,
NULL_TREE, type);
get_identifier (i.name), i.type);
DECL_CHAIN (next) = fields;
fields = next;
}
Expand Down Expand Up @@ -1737,6 +1740,7 @@ declare_handle_contract_violation ()
create_implicit_typedef (viol_name, violation);
DECL_SOURCE_LOCATION (TYPE_NAME (violation)) = BUILTINS_LOCATION;
DECL_CONTEXT (TYPE_NAME (violation)) = current_namespace;
TREE_PUBLIC (TYPE_NAME (violation)) = true;
pushdecl_namespace_level (TYPE_NAME (violation), /*hidden*/true);
pop_namespace ();
pop_nested_namespace (std_node);
Expand All @@ -1761,6 +1765,11 @@ static void
build_contract_handler_call (tree contract,
contract_continuation cmode)
{
/* We may need to declare new types, ensure they are not considered
attached to a named module. */
auto module_kind_override = make_temp_override
(module_kind, module_kind & ~(MK_PURVIEW | MK_ATTACH | MK_EXPORTING));

tree violation = build_contract_violation (contract, cmode);
tree violation_fn = declare_handle_contract_violation ();
tree call = build_call_n (violation_fn, 1, build_address (violation));
Expand Down
8 changes: 8 additions & 0 deletions gcc/testsuite/g++.dg/modules/contracts-5_a.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// PR c++/108205
// Test that the implicitly declared handle_contract_violation function is
// properly matched with a later declaration in an importing TU.
// { dg-additional-options "-fmodules -fcontracts -fcontract-continuation-mode=on" }
// { dg-module-cmi test }

export module test;
export inline void foo(int x) noexcept [[ pre: x != 0 ]] {}
20 changes: 20 additions & 0 deletions gcc/testsuite/g++.dg/modules/contracts-5_b.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// PR c++/108205
// { dg-module-do run }
// { dg-additional-options "-fmodules -fcontracts -fcontract-continuation-mode=on" }

#include <experimental/contract>
import test;

bool saw_violation = false;
void handle_contract_violation(const std::experimental::contract_violation& v) {
saw_violation = true;
}

int main() {
foo(10);
if (saw_violation)
__builtin_abort();
foo(0);
if (!saw_violation)
__builtin_abort();
}

0 comments on commit d3627c7

Please sign in to comment.