public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/c++-contracts] c++: friend contracts are in complete-class context
@ 2022-11-03 19:45 Jason Merrill
0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2022-11-03 19:45 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:e378b7f8250d1e1b029c0254dc17492fa16e9de4
commit e378b7f8250d1e1b029c0254dc17492fa16e9de4
Author: Jason Merrill <jason@redhat.com>
Date: Wed Nov 2 15:21:29 2022 -0400
c++: friend contracts are in complete-class context
Comparing friend contracts to a previous declaration was awkward
because at the point of duplicate_decls we haven't parsed the new ones yet,
and we're about to throw away one of the decls. But conveniently, there's
already defer_guarded_contract_match to handle this.
This reverts commit 9c0d8bfebc32d5e2c35ed61753440fb175a87dcf.
gcc/cp/ChangeLog:
* contracts.cc (check_for_mismatched_contracts):
Only check new_contract for deferred.
(match_deferred_contracts): Set processing_template_decl.
(duplicate_contracts): Call defer_guarded_contract_match
for friend decl. Handle templates.
* decl.cc (duplicate_decls): Use it for templates.
* parser.h (struct cp_parser): Remove declaring_friend_p.
* parser.cc (cp_parser_new): Don't clear it.
(cp_parser_direct_declarator): Don't set it.
(cp_parser_contract_attribute_spec): Don't check it.
* contracts.h (match_contract_conditions): Remove.
gcc/testsuite/ChangeLog:
* g++.dg/contracts/contracts-friend1.C: Revert.
* g++.dg/contracts/contracts-nested-class1.C: Revert.
* g++.dg/contracts/contracts-redecl7.C: Revert.
* g++.dg/contracts/contracts-redecl8.C: Revert.
Diff:
---
gcc/cp/contracts.h | 1 -
gcc/cp/parser.h | 6 ----
gcc/cp/contracts.cc | 21 ++++++++++----
gcc/cp/decl.cc | 11 +-------
gcc/cp/parser.cc | 17 +++--------
gcc/testsuite/g++.dg/contracts/contracts-friend1.C | 12 +++++---
.../g++.dg/contracts/contracts-nested-class1.C | 4 +--
gcc/testsuite/g++.dg/contracts/contracts-redecl7.C | 33 +++++++++++++++++++++-
gcc/testsuite/g++.dg/contracts/contracts-redecl8.C | 3 +-
9 files changed, 64 insertions(+), 44 deletions(-)
diff --git a/gcc/cp/contracts.h b/gcc/cp/contracts.h
index ad382cf187b..4050a38708b 100644
--- a/gcc/cp/contracts.h
+++ b/gcc/cp/contracts.h
@@ -286,7 +286,6 @@ extern bool check_postcondition_result (tree, tree, location_t);
extern tree get_precondition_function (tree);
extern tree get_postcondition_function (tree);
extern void duplicate_contracts (tree, tree);
-extern bool match_contract_conditions (location_t, tree, location_t, tree, contract_matching_context);
extern void match_deferred_contracts (tree);
extern void defer_guarded_contract_match (tree, tree, tree);
extern bool diagnose_misapplied_contracts (tree);
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index f695f4566b4..5737146dd42 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -315,12 +315,6 @@ struct GTY(()) cp_parser {
direct-declarator. */
bool in_declarator_p;
- /* TRUE if the decl-specifier-seq preceding a declarator includes
- the 'friend' specifier. This prevents attributes on friend function
- declarations from being parsed in the complete class context. */
- /* ??? But they should be; maybe use defer_guarded_contract_match? */
- bool declaring_friend_p;
-
/* TRUE if we are presently parsing a template-argument-list. */
bool in_template_argument_list_p;
diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index 6db3b750fda..38eb4ad9bfe 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -1147,9 +1147,8 @@ check_for_mismatched_contracts (tree old_attr, tree new_attr,
return true;
}
- /* Two deferred contracts tentatively match. */
- if (CONTRACT_CONDITION_DEFERRED_P (old_contract)
- && CONTRACT_CONDITION_DEFERRED_P (new_contract))
+ /* A deferred contract tentatively matches. */
+ if (CONTRACT_CONDITION_DEFERRED_P (new_contract))
return false;
/* Compare the conditions of the contracts. We fold immediately to avoid
@@ -1275,6 +1274,9 @@ match_deferred_contracts (tree decl)
gcc_assert(!contract_any_deferred_p (DECL_CONTRACTS (decl)));
+ processing_template_decl_sentinel ptds;
+ processing_template_decl = uses_template_parms (decl);
+
/* Do late contract matching. */
for (tree pending = *tp; pending; pending = TREE_CHAIN (pending))
{
@@ -2093,12 +2095,16 @@ apply_postcondition_to_return (tree expr)
}
/* A subroutine of duplicate_decls. Diagnose issues in the redeclaration of
- guarded functions. Note that attributes on new friend declarations have not
- been processed yet, so we take those from the global above. */
+ guarded functions. */
void
duplicate_contracts (tree newdecl, tree olddecl)
{
+ if (TREE_CODE (newdecl) == TEMPLATE_DECL)
+ newdecl = DECL_TEMPLATE_RESULT (newdecl);
+ if (TREE_CODE (olddecl) == TEMPLATE_DECL)
+ olddecl = DECL_TEMPLATE_RESULT (olddecl);
+
/* Compare contracts to see if they match. */
tree old_contracts = DECL_CONTRACTS (olddecl);
tree new_contracts = DECL_CONTRACTS (newdecl);
@@ -2134,6 +2140,11 @@ duplicate_contracts (tree newdecl, tree olddecl)
new_loc, new_contracts,
cmc_declaration))
return;
+ if (DECL_UNIQUE_FRIEND_P (newdecl))
+ /* Newdecl's contracts are still DEFERRED_PARSE, and we're about to
+ collapse it into olddecl, so stash away olddecl's contracts for
+ later comparison. */
+ defer_guarded_contract_match (olddecl, olddecl, old_contracts);
}
/* Handle cases where contracts are omitted in one or the other
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 9e591d592cf..f4d6ee5dede 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2278,16 +2278,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
gcc_assert (!DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
/* Make sure the contracts are equivalent. */
- tree old_contracts = DECL_CONTRACTS (old_result);
- tree new_contracts = DECL_CONTRACTS (new_result);
- if (old_contracts && new_contracts)
- {
- match_contract_conditions (DECL_SOURCE_LOCATION (old_result),
- old_contracts,
- DECL_SOURCE_LOCATION (new_result),
- new_contracts,
- cmc_declaration);
- }
+ duplicate_contracts (newdecl, olddecl);
/* Remove contracts from old_result so they aren't appended to
old_result by the merge function. */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 96e1537356e..4d4475b80f0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -4310,9 +4310,6 @@ cp_parser_new (cp_lexer *lexer)
/* We are not processing a declarator. */
parser->in_declarator_p = false;
- /* We are not parsing a friend declaration. */
- parser->declaring_friend_p = false;
-
/* We are not processing a template-argument-list. */
parser->in_template_argument_list_p = false;
@@ -23285,10 +23282,7 @@ cp_parser_direct_declarator (cp_parser* parser,
= cp_parser_exception_specification_opt (parser,
flags);
- bool saved_declaring_friend_p = parser->declaring_friend_p;
- parser->declaring_friend_p = friend_p;
attrs = cp_parser_std_attribute_spec_seq (parser);
- parser->declaring_friend_p = saved_declaring_friend_p;
cp_omp_declare_simd_data odsd;
if ((flag_openmp || flag_openmp_simd)
@@ -29635,14 +29629,11 @@ cp_parser_contract_attribute_spec (cp_parser *parser, tree attribute)
cp_parser_require (parser, CPP_COLON, RT_COLON);
- /* Defer the parsing of pre/post contracts inside class definitions.
- Note that friends are not member functions and thus not in the complete
- class context. */
+ /* Defer the parsing of pre/post contracts inside class definitions. */
tree contract;
- if (!assertion_p
- && current_class_type
- && TYPE_BEING_DEFINED (current_class_type)
- && !parser->declaring_friend_p)
+ if (!assertion_p &&
+ current_class_type &&
+ TYPE_BEING_DEFINED (current_class_type))
{
/* Skip until we reach an unenclose ']'. If we ran into an unnested ']'
that doesn't close the attribute, return an error and let the attribute
diff --git a/gcc/testsuite/g++.dg/contracts/contracts-friend1.C b/gcc/testsuite/g++.dg/contracts/contracts-friend1.C
index 01cebb0c2fb..0ccfbe2c7c3 100644
--- a/gcc/testsuite/g++.dg/contracts/contracts-friend1.C
+++ b/gcc/testsuite/g++.dg/contracts/contracts-friend1.C
@@ -3,6 +3,8 @@
// { dg-options "-std=c++2a -fcontracts -fcontract-continuation-mode=on" }
struct X {
+ friend void fn0(X x) [[ pre: x.a > 0 ]] { }
+
friend void fn2(X x);
static void fns0(X x) [[ pre: x.a > 0 ]] { }
static void fns1(X x) [[ pre: x.a > 0 ]];
@@ -22,6 +24,7 @@ int main(int, char**) {
X x;
fn(x); // no contract
+ fn0(x);
fn2(x);
X::fns0(x);
@@ -30,7 +33,8 @@ int main(int, char**) {
return 0;
}
-// { dg-output "default std::handle_contract_violation called: .*.C 17 fn2 .*(\n|\r\n|\r)*" }
-// { dg-output "default std::handle_contract_violation called: .*.C 7 X::fns0 .*(\n|\r\n|\r)*" }
-// { dg-output "default std::handle_contract_violation called: .*.C 8 X::fns1 .*(\n|\r\n|\r)*" }
-// { dg-output "default std::handle_contract_violation called: .*.C 19 X::fns2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 6 fn0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 19 fn2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 9 X::fns0 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 10 X::fns1 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 21 X::fns2 .*(\n|\r\n|\r)*" }
diff --git a/gcc/testsuite/g++.dg/contracts/contracts-nested-class1.C b/gcc/testsuite/g++.dg/contracts/contracts-nested-class1.C
index e6c362ab2a7..05c1cf131c4 100644
--- a/gcc/testsuite/g++.dg/contracts/contracts-nested-class1.C
+++ b/gcc/testsuite/g++.dg/contracts/contracts-nested-class1.C
@@ -16,7 +16,7 @@ struct Outer {
// error about 'p' not being declared because the contracts haven't been
// unified or remapped.
friend void gfn(int p) [[ pre: p > 0 ]];
- friend void gfn(int q) [[ pre: q > 1 ]]; // { dg-error "mismatched contract" }
+ friend void gfn(int q) [[ pre: q > 1 ]]; // { dg-error "'q' was not declared" }
// This should be okay.
friend void gfn2(int q);
@@ -24,4 +24,4 @@ struct Outer {
static int bob;
};
-int Outer::bob{-1};
\ No newline at end of file
+int Outer::bob{-1};
diff --git a/gcc/testsuite/g++.dg/contracts/contracts-redecl7.C b/gcc/testsuite/g++.dg/contracts/contracts-redecl7.C
index 050c8ee3191..e3a57eea632 100644
--- a/gcc/testsuite/g++.dg/contracts/contracts-redecl7.C
+++ b/gcc/testsuite/g++.dg/contracts/contracts-redecl7.C
@@ -19,19 +19,38 @@ int both(int a, T *t) [[ pre: a > 0 ]];
struct T
{
friend int now(int a, T *t);
+ friend int later(int a, T *t) [[ pre: a > 0 ]] [[ pre: t->pri > 0 ]]
+ {
+ printf("later: a: %d, t->pri: %d\n", a, t->pri);
+ return -a * t->pri;
+ }
friend int both(int a, T *t) [[ pre: a > 0 ]]
{
printf("both: a: %d, t->pri: %d\n", a, t->pri);
return -a * t->pri;
}
+
friend int S::now(int a, T *t);
+ friend int hidden(int a, T *t) [[ pre: a > 0 ]] [[ pre: t->pri > 0 ]]
+ {
+ printf("hidden: a: %d, t->pri: %d\n", a, t->pri);
+ return -a * t->pri;
+ }
+ friend int hidden2(int a, T *t) [[ pre: a > 0 ]] [[ pre: t->pri > 0 ]]
+ {
+ printf("hidden2: a: %d, t->pri: %d\n", a, t->pri);
+ return -a * t->pri;
+ }
+
int x{1};
private:
int pri{-10};
};
+int hidden2(int a, T *t) [[ pre: a > 0 ]] [[ pre: t->pri > 0 ]];
+
int S::now(int a, T *t)
{
printf("S::now: a: %d, t->pri: %d\n", a, t->pri);
@@ -51,7 +70,10 @@ int main(int, char**)
s.now(-10, &t);
now(-20, &t);
+ later(-21, &t);
both(-22, &t);
+ hidden(-23, &t);
+ hidden2(-24, &t);
return 0;
}
@@ -59,6 +81,15 @@ int main(int, char**)
// { dg-output "S::now: a: -10, t->pri: -10(\n|\r\n|\r)*" }
// { dg-output "default std::handle_contract_violation called: .*.C 15 now .*(\n|\r\n|\r)*" }
// { dg-output "now: a: -20, t->pri: -10(\n|\r\n|\r)*" }
-// { dg-output "default std::handle_contract_violation called: .*.C 22 both .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 22 later .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 22 later .*(\n|\r\n|\r)*" }
+// { dg-output "later: a: -21, t->pri: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 27 both .*(\n|\r\n|\r)*" }
// { dg-output "both: a: -22, t->pri: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 36 hidden .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 36 hidden .*(\n|\r\n|\r)*" }
+// { dg-output "hidden: a: -23, t->pri: -10(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 41 hidden2 .*(\n|\r\n|\r)*" }
+// { dg-output "default std::handle_contract_violation called: .*.C 41 hidden2 .*(\n|\r\n|\r)*" }
+// { dg-output "hidden2: a: -24, t->pri: -10(\n|\r\n|\r)*" }
diff --git a/gcc/testsuite/g++.dg/contracts/contracts-redecl8.C b/gcc/testsuite/g++.dg/contracts/contracts-redecl8.C
index ffa41dee5e5..933adce79f9 100644
--- a/gcc/testsuite/g++.dg/contracts/contracts-redecl8.C
+++ b/gcc/testsuite/g++.dg/contracts/contracts-redecl8.C
@@ -26,9 +26,8 @@ struct T
return 0;
}
- // friends are not members and thus not in the complete class context.
friend int hidden(int x, T *t)
- [[ pre: x > 1 ]] [[ pre: t->pri > 0 ]] // { dg-error "has no member" }
+ [[ pre: x > 1 ]] [[ pre: t->pri > 0 ]]
{
return x;
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-11-03 19:45 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-03 19:45 [gcc/devel/c++-contracts] c++: friend contracts are in complete-class context Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).