c++: contract condition function linkage

Since the .pre/post functions are implementation details, not ABI artifacts,
we should make them internal when possible, including putting them in the
same COMDAT group with a vague linkage guarded function.

gcc/cp/ChangeLog:

	* contracts.cc (build_contract_condition_function): Set linkage.
	* semantics.c (expand_or_defer_fn_1): Call finish_function_contracts
	here.
	* decl.c (finish_function): Not here.
	* decl2.c (comdat_linkage): Add pre/post fns to same comdat group.

gcc/testsuite/ChangeLog:

	* g++.dg/contracts/contracts-comdat1.C: New test.
diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index 1921e06..6ac9ac1 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -1432,6 +1432,23 @@
   IDENTIFIER_VIRTUAL_P (DECL_NAME (fn)) = false;
   DECL_VIRTUAL_P (fn) = false;
 
+  /* Make these functions internal if we can, i.e. if the guarded function is
+     not vague linkage, or if we can put them in a comdat group with the
+     guarded function.  */
+  if (!DECL_WEAK (fndecl) || HAVE_COMDAT_GROUP)
+    {
+      TREE_PUBLIC (fn) = false;
+      DECL_EXTERNAL (fn) = false;
+      DECL_WEAK (fn) = false;
+      DECL_COMDAT (fn) = false;
+
+      /* We haven't set the comdat group on the guarded function yet, we'll add
+	 this to the same group in comdat_linkage later.  */
+      gcc_assert (!DECL_ONE_ONLY (fndecl));
+
+      DECL_INTERFACE_KNOWN (fn) = true;
+    }
+
   DECL_ARTIFICIAL (fn) = true;
 
   /* Update various inline related declaration properties.  */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 8fa0577..79b977f 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1984,7 +1984,17 @@
 comdat_linkage (tree decl)
 {
   if (flag_weak)
-    make_decl_one_only (decl, cxx_comdat_group (decl));
+    {
+      make_decl_one_only (decl, cxx_comdat_group (decl));
+      if (HAVE_COMDAT_GROUP && flag_contracts && DECL_CONTRACTS (decl))
+	{
+	  symtab_node *n = symtab_node::get (decl);
+	  if (tree pre = DECL_PRE_FN (decl))
+	    cgraph_node::get_create (pre)->add_to_same_comdat_group (n);
+	  if (tree post = DECL_POST_FN (decl))
+	    cgraph_node::get_create (post)->add_to_same_comdat_group (n);
+	}
+    }
   else if (TREE_CODE (decl) == FUNCTION_DECL
 	   || (VAR_P (decl) && DECL_ARTIFICIAL (decl)))
     /* We can just emit function and compiler-generated variables
diff --git a/gcc/testsuite/g++.dg/contracts/contracts-comdat1.C b/gcc/testsuite/g++.dg/contracts/contracts-comdat1.C
new file mode 100644
index 0000000..3384ae6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/contracts-comdat1.C
@@ -0,0 +1,19 @@
+// Contract condition functions should be local symbols in a comdat group with
+// the guarded function.
+
+// { dg-do compile { target { c++20 && comdat_group } } }
+// { dg-additional-options -fcontracts }
+// { dg-final { scan-assembler-not "_Z1fi.pre,comdat" } }
+// { dg-final { scan-assembler-not {(weak|globl)[^\n]*_Z1fi.pre} } }
+
+inline int f(int i)
+  [[ pre: i > 0 ]]
+{
+  return i;
+}
+
+int main()
+{
+  if (f(42) != 42)
+    __builtin_abort ();
+}