Skip to content

Commit e872f18

Browse files
NinaRannsiains
authored andcommitted
inherited in class, early draft
1 parent 3da4030 commit e872f18

File tree

6 files changed

+214
-45
lines changed

6 files changed

+214
-45
lines changed

gcc/cp/parser.cc

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31749,50 +31749,62 @@ void cp_parser_late_contract_condition (cp_parser *parser,
3174931749

3175031750
/* Parse a base in inherited contract list */
3175131751

31752-
tree cp_parser_inherited_contract_base (cp_parser *parser,
31753-
tree fndecl,
31754-
tree_code code)
31752+
tree
31753+
cp_parser_inherited_contract_base (cp_parser *parser, tree fndecl,
31754+
tree_code code)
3175531755
{
3175631756
tree base_contracts = NULL_TREE;
31757-
tree basedecl = cp_parser_class_name (parser,
31758-
/*typename_keyword_p=*/true,
31759-
/*template_keyword_p=*/false, none_type,
31760-
/*check_dependency_p=*/false,
31761-
/*class_head_p=*/false,
31762-
/*is_declaration=*/false);
31757+
tree in_decl = cp_parser_class_name (parser,
31758+
/*typename_keyword_p=*/true,
31759+
/*template_keyword_p=*/false, none_type,
31760+
/*check_dependency_p=*/false,
31761+
/*class_head_p=*/false,
31762+
/*is_declaration=*/false);
3176331763

31764-
if (basedecl == error_mark_node)
31765-
return NULL_TREE;
31764+
if (in_decl == error_mark_node)
31765+
return NULL_TREE;
3176631766

31767-
tree basetype = TYPE_CANONICAL(TREE_TYPE (basedecl));
31768-
if (basetype == error_mark_node)
31767+
tree in_type = TYPE_CANONICAL(TREE_TYPE (in_decl));
31768+
tree base_type = NULL_TREE;
31769+
tree binfo = TYPE_BINFO (DECL_CONTEXT (fndecl));
31770+
tree base_binfo;
31771+
for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
3176931772
{
31770-
error_at (DECL_SOURCE_LOCATION(fndecl), "contracts"
31771-
" can only be inherited from a baseclass ");
31772-
return NULL_TREE;
31773+
if (same_type_p (in_type, TYPE_CANONICAL (BINFO_TYPE (base_binfo))))
31774+
{
31775+
base_type = BINFO_TYPE (base_binfo);
31776+
break;
31777+
}
3177331778
}
3177431779

31775-
tree basefn = look_for_overrides_here (basetype, fndecl);
31776-
if (!basefn)
31777-
{
31778-
error_at (DECL_SOURCE_LOCATION(fndecl), "function does not "
31779-
" override a function in %qT ",
31780-
basetype);
31781-
return NULL_TREE;
31782-
}
31780+
if (!base_type)
31781+
{
31782+
error_at (DECL_SOURCE_LOCATION(fndecl), "contracts"
31783+
" can only be inherited from a direct base class ");
31784+
return NULL_TREE ;
31785+
}
3178331786

31784-
if (DECL_HAS_CONTRACTS_P(basefn))
31785-
{
31786-
contract_match_kind remap_kind = cmk_pre;
31787-
if (code == POSTCONDITION_STMT)
31788-
remap_kind = cmk_post;
31789-
/* We're inheriting basefn's contracts; create a copy of them but
31790-
* replace references to their parms to our parms. */
31787+
tree base_fn = look_for_overrides_here (base_type, fndecl);
31788+
if (!base_fn)
31789+
{
31790+
error_at (DECL_SOURCE_LOCATION (fndecl), "function does not "
31791+
"override a function in %qT ",
31792+
base_type);
31793+
return NULL_TREE ;
31794+
}
3179131795

31792-
base_contracts = copy_and_remap_contracts (fndecl, basefn,
31793-
/* remap_result */false,
31794-
remap_kind);
31795-
}
31796+
if (DECL_HAS_CONTRACTS_P(base_fn))
31797+
{
31798+
contract_match_kind remap_kind = cmk_pre;
31799+
if (code == POSTCONDITION_STMT)
31800+
remap_kind = cmk_post;
31801+
/* We're inheriting basefn's contracts; create a copy of them but
31802+
* replace references to their parms to our parms. */
31803+
31804+
base_contracts = copy_and_remap_contracts (fndecl, base_fn,
31805+
/* remap_result */false,
31806+
remap_kind);
31807+
}
3179631808
// todo warn on empty contracts ?
3179731809
return base_contracts;
3179831810
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// check that we do not get unused warnings for contract check function parameters
2+
// { dg-do compile }
3+
// { dg-options "-std=c++2b -fcontracts -fcontracts-nonattr -fcontracts-on-virtual-functions=P3653" }
4+
5+
6+
void foo() pre inherited(Base); // { dg-error "inherited contracts are only available on member functions" }
7+
8+
struct Base
9+
{
10+
virtual void f() pre (true){};
11+
};
12+
13+
struct Bob;
14+
struct Child0 : Base
15+
{
16+
virtual void f() pre inherited(Base,); // { dg-error "expected class-name at end of input" }
17+
virtual void g1() pre inherited(Base); // { dg-error "does not override" }
18+
virtual void g2() pre inherited(Bob); // { dg-error "contracts can only be inherited from a direct base class" }
19+
virtual void g3() pre inherited(int); // { dg-error "expected" }
20+
21+
void h() pre inherited(Base);// { dg-error "contracts can only appear on a virtual function" }
22+
};
23+
24+
struct GChild: Child0
25+
{
26+
virtual void f() pre inherited(Base); // { dg-error "contracts can only be inherited from a direct base class" }
27+
};
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// { dg-do run }
2+
// { dg-options "-std=c++2a -fcontracts -fcontracts-nonattr -fcontracts-on-virtual-functions=P3653 -g3" }
3+
#include <cassert>
4+
5+
struct contract
6+
{
7+
int checked = 0;
8+
};
9+
10+
contract a, b, c;
11+
12+
bool
13+
checkA ()
14+
{
15+
a.checked++;
16+
return true;
17+
}
18+
19+
bool
20+
checkB ()
21+
{
22+
b.checked++;
23+
return true;
24+
}
25+
26+
bool
27+
checkC ()
28+
{
29+
c.checked++;
30+
return true;
31+
}
32+
33+
void
34+
clear_checks ()
35+
{
36+
a.checked = b.checked = c.checked = 0;
37+
38+
}
39+
40+
struct Base1
41+
{
42+
virtual int f1(const int i) post (checkA()){ return 1;};
43+
virtual int f2(const int i) pre (checkA()) post (checkB()){ return 1;};
44+
45+
};
46+
47+
48+
49+
struct Base2
50+
{
51+
virtual int f1(const int i) pre (checkB()){ return 1;};
52+
virtual int f2(const int i) { return 1;};
53+
54+
};
55+
56+
struct Base3
57+
{
58+
virtual int f1(const int i) pre (checkB()) pre (checkC()){ return 1;};
59+
virtual int f2(const int i) { return 1;};
60+
61+
};
62+
63+
64+
struct Child0 : Base1
65+
{
66+
virtual int f1(const int i) pre inherited (Base1) pre(checkC());
67+
virtual int f2(const int i) post inherited (Base1){ return 1;}
68+
};
69+
70+
struct Child1 : Base1, private Base2, protected Base3
71+
{
72+
virtual int f1(const int i) pre inherited (Base1, Base2, Base3){ return 1;}
73+
virtual int f2(const int i) post inherited (Base1, Base2, Base3){ return 1;}
74+
};
75+
76+
struct GChild : Child0
77+
{
78+
virtual int f1(const int i){ return 1;}
79+
virtual int f2(const int i) post inherited (Child0){ return 1;}
80+
};
81+
82+
int Child0::f1(const int i){ return 3;}
83+
84+
int main()
85+
{
86+
87+
Child0 c0;
88+
89+
clear_checks ();
90+
c0.f1(2);
91+
assert (a.checked == 0);
92+
assert (b.checked == 0);
93+
assert (c.checked > 0);
94+
95+
clear_checks ();
96+
c0.f2(2);
97+
assert (a.checked == 0);
98+
assert (b.checked > 0);
99+
assert (c.checked == 0);
100+
101+
102+
Child1 c1;
103+
104+
clear_checks ();
105+
c1.f1(2);
106+
assert (a.checked == 0);
107+
assert (b.checked > 0);
108+
assert (c.checked > 0);
109+
110+
clear_checks ();
111+
c1.f2(2);
112+
assert (a.checked == 0);
113+
assert (b.checked > 0);
114+
assert (c.checked == 0);
115+
116+
GChild g;
117+
118+
clear_checks ();
119+
g.f1(2);
120+
assert (a.checked == 0);
121+
assert (b.checked == 0);
122+
assert (c.checked > 0);
123+
124+
clear_checks ();
125+
c1.f2(2);
126+
assert (a.checked == 0);
127+
assert (b.checked > 0);
128+
assert (c.checked == 0);
129+
130+
}

gcc/testsuite/g++.dg/contracts/cpp26/contracts-redecl.C

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ int f1(int a) pre ( a < 0 ); // { dg-error "mismatched contract" }
4343

4444
struct Base
4545
{
46-
virtual int f(int a) pre (a > 0); // { dg-error "Contracts can not be added to virtual functions" }
46+
virtual int f(int a) pre (a > 0); // { dg-error "Contracts cannot be added to virtual functions" }
4747
};
4848

4949
struct Child : Base
5050
{
51-
int f(int a) pre (a < 0); // { dg-error "Contracts can not be added to virtual functions" }
51+
int f(int a) pre (a < 0); // { dg-error "Contracts cannot be added to virtual functions" }
5252
};
5353

5454
struct F1
@@ -75,11 +75,11 @@ void T1::vfun(int m, double n)
7575
void T1::vfun(int m, double n) pre(true); // { dg-error "declaration adds contracts" }
7676

7777
struct Foo {
78-
virtual void f10 (int) pre ( false ) {} // { dg-error "Contracts can not be added to virtual functions" }
78+
virtual void f10 (int) pre ( false ) {} // { dg-error "Contracts cannot be added to virtual functions" }
7979
};
8080

8181
struct Bar : Foo {
82-
void f10 (int n = 0) override pre ( false ); // { dg-error "Contracts can not be added to virtual functions" }
82+
void f10 (int n = 0) override pre ( false ); // { dg-error "Contracts cannot be added to virtual functions" }
8383
};
8484

8585
// we currently don't diagnose an error here if the original contract was erroneous.

gcc/testsuite/g++.dg/contracts/cpp26/preexisting_tests.C

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ namespace parsing_trailing_return_type_test {
2424

2525
namespace parsing_virtual_test {
2626
struct A {
27-
virtual void f(int i) // { dg-error "Contracts can not be added to virtual functions" }
27+
virtual void f(int i) // { dg-error "Contracts cannot be added to virtual functions" }
2828
pre(i >= 0);
2929
};
3030

3131
struct B : A {
32-
void f(int i) override final // { dg-error "Contracts can not be added to virtual functions" }
32+
void f(int i) override final // { dg-error "Contracts cannot be added to virtual functions" }
3333
pre(i >= 0);
3434
};
3535

3636
struct C : A {
37-
void f(int i) override // { dg-error "Contracts can not be added to virtual functions" }
37+
void f(int i) override // { dg-error "Contracts cannot be added to virtual functions" }
3838
pre(i >= 0) = 0;
3939
};
4040
}
@@ -45,7 +45,7 @@ namespace parsing_default_delete_pure_test {
4545
struct X {
4646
X() pre(a) = default;
4747
X(const X&) pre(b) = delete;
48-
virtual void f() pre(c) = 0; // { dg-error "Contracts can not be added to virtual functions" }
48+
virtual void f() pre(c) = 0; // { dg-error "Contracts cannot be added to virtual functions" }
4949
};
5050
}
5151

gcc/testsuite/g++.dg/contracts/cpp26/virtual_func_none.C

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33

44
struct Base
55
{
6-
virtual int f1() pre(true); // { dg-error "Contracts can not be added to virtual functions" }
6+
virtual int f1() pre(true); // { dg-error "Contracts cannot be added to virtual functions" }
77
virtual int f2();
88

99
};
1010
struct Child : Base
1111
{
12-
int f2() pre(true); // { dg-error "Contracts can not be added to virtual functions" }
12+
int f2() pre(true); // { dg-error "Contracts cannot be added to virtual functions" }
1313

1414
};
1515

0 commit comments

Comments
 (0)