Skip to content

Commit e354b73

Browse files
committed
fixing detection of non cont parameters in redeclarations. Diagnostic messages are minimum effort and can be improved
1 parent a0dfe96 commit e354b73

File tree

10 files changed

+389
-67
lines changed

10 files changed

+389
-67
lines changed

gcc/cp/contracts.cc

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2782,30 +2782,58 @@ constify_contract_access(tree decl)
27822782
return decl;
27832783
}
27842784

2785-
/* Do not allow non-const by-value params being used in postconditions. */
2785+
/* If declaration DECL is a PARM_DECL and it appears in a postcondition, then
2786+
check that it is not a non-const by-value param. LOCATION is where the
2787+
expression was found and is used for diagnostic purposes. */
27862788

2787-
bool
2788-
maybe_reject_param_in_postcondition (tree decl)
2789+
void
2790+
maybe_reject_param_in_postcondition (tree decl, location_t location)
27892791
{
27902792
if (flag_contracts_nonattr
2791-
&& !TREE_READONLY (decl)
27922793
&& TREE_CODE (decl) == PARM_DECL
27932794
&& should_constify_contract
27942795
&& processing_postcondition
2795-
&& !dependent_type_p (TREE_TYPE (decl))
2796-
&& !CP_TYPE_CONST_P (TREE_TYPE (decl))
27972796
&& !(REFERENCE_REF_P (decl)
27982797
&& TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL)
27992798
/* Return value parameter has DECL_ARTIFICIAL flag set. The flag
28002799
* presence of the flag should be sufficient to distinguish the
28012800
* return value parameter in this context. */
28022801
&& !(DECL_ARTIFICIAL (decl)))
28032802
{
2804-
error_at (DECL_SOURCE_LOCATION (decl),
2805-
"a value parameter used in a postcondition must be const");
2806-
return true;
2803+
set_parm_used_in_post (decl);
2804+
2805+
if (!CP_TYPE_CONST_P(TREE_TYPE (decl)) && !TREE_READONLY(decl))
2806+
{
2807+
error_at (location,
2808+
"a value parameter used in a postcondition must be const");
2809+
inform (DECL_SOURCE_LOCATION(decl), "parameter declared here");
2810+
}
2811+
}
2812+
}
2813+
2814+
/* Check if parameters used in postconditions are const qualified on
2815+
a redeclaration that does not specify contracts. */
2816+
2817+
void
2818+
check_param_in_redecl (tree olddecl, tree newdecl)
2819+
{
2820+
tree t1 = FUNCTION_FIRST_USER_PARM(olddecl);
2821+
tree t2 = FUNCTION_FIRST_USER_PARM(newdecl);
2822+
for (; t1 && t1 != void_list_node;
2823+
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
2824+
{
2825+
if (parm_used_in_post_p(t1))
2826+
{
2827+
set_parm_used_in_post (t2);
2828+
if (!CP_TYPE_CONST_P(TREE_TYPE (t2)) && !TREE_READONLY(t2))
2829+
{
2830+
error_at (DECL_SOURCE_LOCATION(t2),
2831+
"value parameter %qE used in a postcondition must be const", t2);
2832+
inform (DECL_SOURCE_LOCATION(olddecl),
2833+
"previous declaration here");
2834+
}
2835+
}
28072836
}
2808-
return false;
28092837
}
28102838

28112839
void
@@ -3277,8 +3305,9 @@ p2900_duplicate_contracts (tree newdecl, tree olddecl)
32773305

32783306
if (old_contracts && !new_contracts)
32793307
/* We allow re-declarations to omit contracts declared on the initial decl.
3280-
In fact, this is required if the conditions contain lambdas. */
3281-
;
3308+
In fact, this is required if the conditions contain lambdas. Check if
3309+
all the parameters are correctly const qualified. */
3310+
check_param_in_redecl (olddecl, newdecl);
32823311
else if (contract_any_deferred_p (new_contracts))
32833312
/* TODO: stash these and figure out how to process them later. */
32843313
;

gcc/cp/cp-tree.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8943,8 +8943,8 @@ extern tree grok_contract (tree, tree, tree, cp_expr, location_t);
89438943
extern tree finish_contract_condition (cp_expr);
89448944
extern void update_late_contract (tree, tree, cp_expr);
89458945
extern tree constify_contract_access (tree);
8946-
extern bool maybe_reject_param_in_postcondition (tree);
8947-
8946+
extern void maybe_reject_param_in_postcondition (tree, location_t);
8947+
extern void check_param_in_redecl (tree, tree);
89488948
extern tree view_as_const (tree);
89498949
extern tree maybe_contract_wrap_call (tree, tree);
89508950
extern bool emit_contract_wrapper_func (bool);
@@ -9025,6 +9025,24 @@ strip_contract_const_wrapper (tree exp)
90259025
return exp;
90269026
}
90279027

9028+
/* Indicate if PARM_DECL DECL is ODR used in a postcondition. */
9029+
9030+
inline void
9031+
set_parm_used_in_post (tree decl, bool constify = true)
9032+
{
9033+
gcc_checking_assert (TREE_CODE (decl) == PARM_DECL);
9034+
decl->base.public_flag = constify;
9035+
}
9036+
9037+
/* Test if PARM_DECL is ODR used in a postcondition. */
9038+
9039+
inline bool
9040+
parm_used_in_post_p (const_tree decl)
9041+
{
9042+
/* Check if this parameter is odr used within a function's postcondition */
9043+
return ((TREE_CODE (decl) == PARM_DECL) && decl->base.public_flag);
9044+
}
9045+
90289046
/* Inline bodies. */
90299047

90309048
inline tree

gcc/cp/decl.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
22732273
declaration of the function or function template in the
22742274
translation unit." */
22752275
check_no_redeclaration_friend_default_args (olddecl, newdecl);
2276+
22762277
}
22772278
}
22782279
}

gcc/cp/pt.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22373,7 +22373,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
2237322373
/* force_paren_expr can also create a VIEW_CONVERT_EXPR. */
2237422374
RETURN (finish_parenthesized_expr (op));
2237522375

22376-
maybe_reject_param_in_postcondition (op);
22376+
maybe_reject_param_in_postcondition (op, EXPR_LOCATION (t));
2237722377

2237822378
if (flag_contracts_nonattr && should_constify_contract
2237922379
&& processing_contract_condition)

gcc/cp/search.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,8 @@ check_override_contracts (tree fndecl)
22732273
inform (DECL_SOURCE_LOCATION (basefn),
22742274
"overridden function is %qD", basefn);
22752275
}
2276+
2277+
check_param_in_redecl (basefn, fndecl);
22762278
}
22772279
}
22782280
}

gcc/cp/semantics.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5019,7 +5019,7 @@ finish_id_expression_1 (tree id_expression,
50195019
}
50205020
}
50215021

5022-
maybe_reject_param_in_postcondition (decl);
5022+
maybe_reject_param_in_postcondition (decl, location);
50235023
if (flag_contracts_nonattr && should_constify_contract
50245024
&& processing_contract_condition)
50255025
decl = constify_contract_access(decl);
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// { dg-do compile }
2+
// { dg-options "-std=c++23 -fcontracts -fcontracts-nonattr -fcontracts-nonattr-inheritance-mode=P3653 " }
3+
4+
struct NTClass {
5+
//TODO, make non trivial when https://github.com/NinaRanns/gcc/issues/21 is solved
6+
// NTClass(){};
7+
// ~NTClass(){};
8+
};
9+
10+
template <typename... ARGS>
11+
bool check(ARGS... args){ return true;}
12+
13+
14+
struct Base
15+
{
16+
virtual void f (const NTClass i) post (check (i));
17+
virtual void f (const int i) post (check (i));
18+
19+
20+
} ;
21+
22+
struct Derived : Base
23+
{
24+
void f (NTClass i); // { dg-error "used in a postcondition must be const" }
25+
};
26+
27+
struct DerivedV : virtual Base
28+
{
29+
void f (NTClass i); // { dg-error "used in a postcondition must be const" }
30+
};
31+
32+
template<typename T>
33+
struct DerivedT : Base
34+
{
35+
void f (NTClass i) {};
36+
37+
void f (T i) {};
38+
};
39+
40+
template<typename T>
41+
struct DerivedTV : virtual Base
42+
{
43+
void f (NTClass i) {};
44+
45+
void f (T i) {};
46+
};
47+
48+
template<typename T>
49+
struct BaseT
50+
{
51+
virtual void f (const NTClass i) post (check (i));
52+
53+
virtual void f (const T i) post (check (i));
54+
};
55+
56+
template<typename T>
57+
struct DerivedTT : BaseT<T>
58+
{
59+
void f (NTClass i) {};
60+
61+
void f (T i) {};
62+
};
63+
64+
template <typename T>
65+
struct DerivedTVT : virtual BaseT<T>
66+
{
67+
void f (NTClass i) {};
68+
69+
void f (T i) {};
70+
};
71+
72+
// adding DerivedT2 for diagnostic disambiguation purposes
73+
template<typename T>
74+
struct DerivedT2 : Base
75+
{
76+
void f (NTClass i) {};
77+
78+
void f (T i) {};
79+
};
80+
81+
// adding DerivedTV2 for diagnostic disambiguation purposes
82+
template<typename T>
83+
struct DerivedTV2 : virtual Base
84+
{
85+
void f (NTClass i) {};
86+
87+
void f (T i) {};
88+
};
89+
90+
template<typename T>
91+
struct DerivedTT2 : BaseT<T>
92+
{
93+
void f (NTClass i) {};
94+
95+
void f (int i) {};
96+
};
97+
98+
template <typename T>
99+
struct DerivedTVT2 : virtual BaseT<T>
100+
{
101+
void f (NTClass i) {};
102+
103+
void f (int i) {};
104+
};
105+
106+
107+
int main()
108+
{
109+
DerivedT<int> dt;
110+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 35 }
111+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 37 }
112+
113+
DerivedTV<int> dvt;
114+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 43 }
115+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 45 }
116+
117+
118+
DerivedTT<int> dt2;
119+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 59 }
120+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 61 }
121+
122+
DerivedTVT<int> dvt2;
123+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 67 }
124+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 69 }
125+
126+
127+
DerivedT2<char> dtc;
128+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 76 }
129+
130+
DerivedTV2<char> dvtc;
131+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 85 }
132+
133+
DerivedTT2<char> dtc2;
134+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 93 }
135+
136+
DerivedTVT2<char> dvtc2;
137+
// { dg-error {used in a postcondition must be const} "" { target *-*-* } 101 }
138+
139+
}

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

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -45,54 +45,3 @@ struct Baz
4545
void i(const int x) post(x, x); // { dg-error "expected conditional-expression" }
4646
};
4747

48-
void postcond(int x) post(x >= 0); // { dg-error "a value parameter used in a postcondition must be const" }
49-
50-
struct PostCond {
51-
void postcond(int x) post(x >= 0); // { dg-error "a value parameter used in a postcondition must be const" }
52-
template<class T> void postcond2(T x) post(x >= 0);
53-
};
54-
55-
template <class T> void
56-
postcond3(T x) post(x >= 0);
57-
58-
void postcond4(const int y, int x) post(x >= 0); // { dg-error "a value parameter used in a postcondition must be const" }
59-
60-
void postcond5(int y, const int x) post(x >= 0);
61-
62-
template <typename T>
63-
struct Base
64-
{
65-
virtual int f(const int a) pre( a > 5 ) post( a > 7) { return a;}; // { dg-error "Contracts can not be added to virtual functions" }
66-
int g(const int a) pre( a > 5 ) post( a > 7) { return a;};
67-
virtual int h(int a) pre( a > 5 ) post( a > 7) { return a;}; // { dg-error "a value parameter used in a postcondition must be const" }
68-
// { dg-error {Contracts can not be added to virtual functions} "" { target *-*-* } .-1 }
69-
int i(int a) pre( a > 5 ) post( a > 7) { return a;}; // { dg-error "a value parameter used in a postcondition must be const" }
70-
};
71-
72-
73-
void postcond6()
74-
{
75-
Base<int> b;
76-
b.f(6);
77-
b.g(6);
78-
b.h(6);
79-
b.i(6);
80-
}
81-
82-
template<class T>
83-
void
84-
PostCond::postcond2(T x) post (x >= 0) // { dg-error "a value parameter used in a postcondition must be const" }
85-
{ x; }
86-
87-
template <class T>
88-
void
89-
postcond3(T x) post(x >= 0)
90-
{ }
91-
92-
void postcond7()
93-
{
94-
PostCond p;
95-
p.postcond2 (2);
96-
postcond3 (4); // { dg-error "a value parameter used in a postcondition must be const" "" {target *-*-* } 56 }
97-
98-
}

0 commit comments

Comments
 (0)