Bootstrapped/regtested on x86_64-pc-linux-gnu.
-- >8 --
`tsubst_function_decl()' associates uninstantiated contracts with a
function template instantiation. If an explicit instantiation is
encountered before a later redeclaration provides the definition,
those contracts can still refer to PARM_DECLs from the earlier
declaration.
Therefore, we should always regererate the contracts from the current
code_pattern in `regenerate_decl_from_template()' when either DECL
or pattern has contracts.
PR c++/125712
gcc/cp/ChangeLog:
* pt.cc (regenerate_decl_from_template): Regenerate contracts
from the current code pattern.
gcc/testsuite/ChangeLog:
* g++.dg/contracts/cpp26/pr125712.C: New test.
Signed-off-by: Wang Jinghao <[email protected]>
---
gcc/cp/pt.cc | 25 +++++-----
.../g++.dg/contracts/cpp26/pr125712.C | 48 +++++++++++++++++++
2 files changed, 61 insertions(+), 12 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/pr125712.C
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 4b4b0ac8dea..217ff8c503a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -28546,18 +28546,19 @@ regenerate_decl_from_template (tree decl, tree tmpl,
tree args)
OLD_PARM_DECL_P (t) = 1;
}
- if (tree attr = get_fn_contract_specifiers (decl))
- {
- /* If we're regenerating a specialization, the contracts will have
- been copied from the most general template. Replace those with
- the ones from the actual specialization. */
- tree tmpl = DECL_TI_TEMPLATE (decl);
- if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
- attr = get_fn_contract_specifiers (code_pattern);
-
- tsubst_contract_specifiers (attr, decl, args,
- tf_warning_or_error, code_pattern);
- }
+ /* The contracts on DECL may predate a later redeclaration of the
+ template, or have been copied from a more general template. We should
+ use the contracts from the current pattern. */
+ tree decl_contracts = get_fn_contract_specifiers (decl);
+ tree pattern_contracts = get_fn_contract_specifiers (code_pattern);
+ /* There are four cases:
+ neither has contracts, so there is nothing to do;
+ only the pattern has contracts, so add them to DECL;
+ only DECL has contracts, so remove them;
+ or both have contracts, so rebuild DECL's from the pattern. */
+ if (decl_contracts || pattern_contracts)
+ tsubst_contract_specifiers (pattern_contracts, decl, args,
+ tf_warning_or_error, code_pattern);
/* Merge additional specifiers from the CODE_PATTERN. */
if (DECL_DECLARED_INLINE_P (code_pattern)
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/pr125712.C
b/gcc/testsuite/g++.dg/contracts/cpp26/pr125712.C
new file mode 100644
index 00000000000..daa2c8f3bd4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/pr125712.C
@@ -0,0 +1,48 @@
+// PR c++/125712
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-fcontracts
-fcontract-evaluation-semantic=observe" }
+// { dg-skip-if "requires hosted libstdc++ for stdc++exp" { ! hostedlib } }
+
+template<typename>
+ void f (bool p) pre (p);
+template void f<int> (bool);
+template<typename>
+ void f (bool) {}
+
+template<typename T>
+ struct Add
+ {
+ template<typename U> void f (U) {}
+ };
+template<> template<typename U>
+ void Add<int>::f (U u) pre (u) {}
+
+template<typename T>
+ struct Remove
+ {
+ template<typename U> void f (U u) pre (u) {}
+ };
+template<> template<typename U>
+ void Remove<int>::f (U) {}
+
+template<typename T>
+ struct Replace
+ {
+ template<typename U> void f (U u) pre (u) {}
+ };
+template<> template<typename U>
+ void Replace<int>::f (U u) pre (u) {}
+
+int
+main ()
+{
+ f<int> (true);
+ Add<int>{}.f (false);
+ Remove<int>{}.f (false);
+ Replace<int>{}.f (false);
+}
+
+// { dg-output {contract violation in function void Add<T>::f\(U\) \[with U =
bool; T = int\] at .*:18: u(\n|\r\n|\r)} }
+// { dg-output {\[assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no\](\n|\r\n|\r)} }
+// { dg-output {contract violation in function void Replace<T>::f\(U\) \[with
U = bool; T = int\] at .*:34: u(\n|\r\n|\r)} }
+// { dg-output {\[assertion_kind: pre, semantic: observe, mode:
predicate_false, terminating: no\](\n|\r\n|\r)} }
--
2.52.0